new syntax: |label|

This commit is contained in:
Roberto Ierusalimschy 2000-04-10 16:21:14 -03:00
parent c3b73cbeb8
commit 0810bc707f
1 changed files with 97 additions and 52 deletions

149
lparser.c
View File

@ -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 ** LL(1) Parser and code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -36,6 +36,7 @@ typedef struct Constdesc {
typedef struct Breaklabel { typedef struct Breaklabel {
struct Breaklabel *previous; /* chain */ struct Breaklabel *previous; /* chain */
TString *label;
int breaklist; int breaklist;
int stacklevel; int stacklevel;
} Breaklabel; } 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, static void luaI_registerlocalvar (LexState *ls, TString *varname,
int line) { int line) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
@ -317,6 +326,7 @@ static int getvarname (LexState *ls, expdesc *var) {
static void enterbreak (FuncState *fs, Breaklabel *bl) { static void enterbreak (FuncState *fs, Breaklabel *bl) {
bl->stacklevel = fs->stacklevel; bl->stacklevel = fs->stacklevel;
bl->label = NULL;
bl->breaklist = NO_JUMP; bl->breaklist = NO_JUMP;
bl->previous = fs->bl; bl->previous = fs->bl;
fs->bl = 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) { static void func_onstack (LexState *ls, FuncState *func) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
Proto *f = fs->f; Proto *f = fs->f;
@ -419,7 +443,7 @@ static int explist1 (LexState *ls) {
expr(ls, &v); expr(ls, &v);
n++; n++;
} }
luaK_tostack(ls, &v, 0); luaK_tostack(ls, &v, 0); /* keep open number of values of last expression */
return n; return n;
} }
@ -427,12 +451,12 @@ static int explist1 (LexState *ls) {
static int explist (LexState *ls) { static int explist (LexState *ls) {
/* explist -> [ explist1 ] */ /* explist -> [ explist1 ] */
switch (ls->token) { switch (ls->token) {
case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_UNTIL: case TK_NUMBER: case TK_STRING: case TK_NIL: case '{':
case TK_EOS: case ';': case ')': case TK_FUNCTION: case '(': case TK_NAME: case '%':
return 0; /* empty list */ case TK_NOT: case '-': /* first `expr' */
default:
return explist1(ls); 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) { static int stat (LexState *ls) {
int line = ls->linenumber; /* may be needed for error messages */ int line = ls->linenumber; /* may be needed for error messages */
switch (ls->token) { switch (ls->token) {
case TK_IF: /* stat -> ifstat */ case TK_IF: /* stat -> ifstat */
ifstat(ls, line); ifstat(ls, line);
break; return 1;
case TK_WHILE: /* stat -> whilestat */ case TK_WHILE: /* stat -> whilestat */
whilestat(ls, line); 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 */ setline_and_next(ls); /* skip DO */
block(ls); block(ls);
check_END(ls, TK_DO, line); check_END(ls, TK_DO, line);
break; return 1;
}
case TK_REPEAT: /* stat -> repeatstat */ case TK_REPEAT: /* stat -> repeatstat */
repeatstat(ls, line); repeatstat(ls, line);
break; return 1;
case TK_FUNCTION: /* stat -> funcstat */ case TK_FUNCTION: /* stat -> funcstat */
funcstat(ls, line); funcstat(ls, line);
break; return 1;
case TK_LOCAL: /* stat -> localstat */ case TK_LOCAL: /* stat -> localstat */
localstat(ls); localstat(ls);
break; return 1;
case TK_NAME: case '%': /* stat -> namestat */ case TK_NAME: case '%': /* stat -> namestat */
namestat(ls); 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: default:
return 0; /* no statement */ 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 chunk (LexState *ls) { static void label (LexState *ls, Breaklabel *bl) {
/* chunk -> { stat [;] } ret */ /* label -> [ '|' NAME '|' ] */
while (stat(ls)) { if (optional(ls, '|')) {
LUA_ASSERT(ls->L, ls->fs->stacklevel == ls->fs->nlocalvar, enterbreak(ls->fs, bl);
"stack size != # local vars"); bl->label = str_checkname(ls);
optional(ls, ';'); check(ls, '|');
} }
ret(ls); /* optional return */ else
bl->label = NULL; /* there is no label */
}
static void chunk (LexState *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");
if (bl.label)
leavebreak(ls->fs, &bl);
} while (a == 1);
} }