From 0810bc707f98f05a2d598e6a00cb33280d16cf89 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 10 Apr 2000 16:21:14 -0300 Subject: new syntax: |label| --- lparser.c | 143 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 94 insertions(+), 49 deletions(-) diff --git a/lparser.c b/lparser.c index f49d6135..61882800 100644 --- a/lparser.c +++ b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.78 2000/04/07 13:13:11 roberto Exp roberto $ +** $Id: lparser.c,v 1.79 2000/04/07 19:35:20 roberto Exp roberto $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -36,6 +36,7 @@ typedef struct Constdesc { typedef struct Breaklabel { struct Breaklabel *previous; /* chain */ + TString *label; int breaklist; int stacklevel; } Breaklabel; @@ -171,6 +172,14 @@ static TString *str_checkname (LexState *ls) { } +static TString *optionalname (LexState *ls) { + if (ls->token == TK_NAME) + return str_checkname(ls); + else + return NULL; +} + + static void luaI_registerlocalvar (LexState *ls, TString *varname, int line) { FuncState *fs = ls->fs; @@ -317,6 +326,7 @@ static int getvarname (LexState *ls, expdesc *var) { static void enterbreak (FuncState *fs, Breaklabel *bl) { bl->stacklevel = fs->stacklevel; + bl->label = NULL; bl->breaklist = NO_JUMP; bl->previous = fs->bl; fs->bl = bl; @@ -330,6 +340,20 @@ static void leavebreak (FuncState *fs, Breaklabel *bl) { } +static Breaklabel *findlabel (FuncState *fs, TString *name) { + Breaklabel *bl; + for (bl=fs->bl; bl; bl=bl->previous) { + if (bl->label == name) + return bl; + } + if (name) /* label not found: choose appropriate error message */ + luaX_syntaxerror(fs->ls, "break not inside given label", name->str); + else + luaK_error(fs->ls, "break not inside while or repeat loop"); + return NULL; /* to avoid warnings */ +} + + static void func_onstack (LexState *ls, FuncState *func) { FuncState *fs = ls->fs; Proto *f = fs->f; @@ -419,7 +443,7 @@ static int explist1 (LexState *ls) { expr(ls, &v); n++; } - luaK_tostack(ls, &v, 0); + luaK_tostack(ls, &v, 0); /* keep open number of values of last expression */ return n; } @@ -427,12 +451,12 @@ static int explist1 (LexState *ls) { static int explist (LexState *ls) { /* explist -> [ explist1 ] */ switch (ls->token) { - case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_UNTIL: - case TK_EOS: case ';': case ')': - return 0; /* empty list */ - - default: + case TK_NUMBER: case TK_STRING: case TK_NIL: case '{': + case TK_FUNCTION: case '(': case TK_NAME: case '%': + case TK_NOT: case '-': /* first `expr' */ return explist1(ls); + default: + return 0; /* empty list */ } } @@ -998,44 +1022,73 @@ static void namestat (LexState *ls) { } +static void retstat (LexState *ls) { + /* stat -> RETURN explist */ + FuncState *fs = ls->fs; + setline_and_next(ls); /* skip RETURN */ + explist(ls); + luaK_code1(fs, OP_RETURN, ls->fs->nlocalvar); + fs->stacklevel = fs->nlocalvar; /* removes all temp values */ +} + + +static void breakstat (LexState *ls) { + /* stat -> BREAK [NAME] */ + FuncState *fs = ls->fs; + Breaklabel *bl; + int currentlevel = fs->stacklevel; + setline_and_next(ls); /* skip BREAK */ + bl = findlabel(fs, optionalname(ls)); + luaK_adjuststack(fs, currentlevel - bl->stacklevel); + luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); + fs->stacklevel = currentlevel; +} + + static int stat (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->token) { case TK_IF: /* stat -> ifstat */ ifstat(ls, line); - break; + return 1; case TK_WHILE: /* stat -> whilestat */ whilestat(ls, line); - break; + return 1; - case TK_DO: { /* stat -> DO block END */ + case TK_DO: /* stat -> DO block END */ setline_and_next(ls); /* skip DO */ block(ls); check_END(ls, TK_DO, line); - break; - } + return 1; case TK_REPEAT: /* stat -> repeatstat */ repeatstat(ls, line); - break; + return 1; case TK_FUNCTION: /* stat -> funcstat */ funcstat(ls, line); - break; + return 1; case TK_LOCAL: /* stat -> localstat */ localstat(ls); - break; + return 1; case TK_NAME: case '%': /* stat -> namestat */ namestat(ls); - break; + return 1; + + case TK_RETURN: /* stat -> retstat */ + retstat(ls); + return 2; /* must be last statement */ + + case TK_BREAK: /* stat -> breakstat */ + breakstat(ls); + return 2; /* must be last statement */ default: return 0; /* no statement */ } - return 1; } @@ -1092,44 +1145,36 @@ static void body (LexState *ls, int needself, int line) { } -static void ret (LexState *ls) { - /* ret -> [RETURN explist sc | BREAK sc] */ - FuncState *fs = ls->fs; - switch (ls->token) { - case TK_RETURN: { - setline_and_next(ls); /* skip RETURN */ - explist(ls); - luaK_code1(fs, OP_RETURN, ls->fs->nlocalvar); - fs->stacklevel = fs->nlocalvar; /* removes all temp values */ - optional(ls, ';'); - break; - } - case TK_BREAK: { - Breaklabel *bl = fs->bl; - int currentlevel = fs->stacklevel; - if (bl == NULL) - luaK_error(ls, "break not inside while or repeat loop"); - - setline_and_next(ls); /* skip BREAK */ - luaK_adjuststack(fs, currentlevel - bl->stacklevel); - luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); - optional(ls, ';'); - fs->stacklevel = currentlevel; - break; - } +/* }====================================================================== */ + + +static void label (LexState *ls, Breaklabel *bl) { + /* label -> [ '|' NAME '|' ] */ + if (optional(ls, '|')) { + enterbreak(ls->fs, bl); + bl->label = str_checkname(ls); + check(ls, '|'); } + else + bl->label = NULL; /* there is no label */ } -/* }====================================================================== */ - static void chunk (LexState *ls) { - /* chunk -> { stat [;] } ret */ - while (stat(ls)) { + /* chunk -> { [label] stat [';'] } */ + Breaklabel bl; + int a; + do { + label(ls, &bl); + a = stat(ls); + if (a != 0) + optional(ls, ';'); + else if (bl.label) + luaK_error(ls, "label without a statement"); LUA_ASSERT(ls->L, ls->fs->stacklevel == ls->fs->nlocalvar, "stack size != # local vars"); - optional(ls, ';'); - } - ret(ls); /* optional return */ + if (bl.label) + leavebreak(ls->fs, &bl); + } while (a == 1); } -- cgit v1.2.3-55-g6feb