diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2000-04-10 16:21:14 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2000-04-10 16:21:14 -0300 |
commit | 0810bc707f98f05a2d598e6a00cb33280d16cf89 (patch) | |
tree | 5fefa71b4f7427eb3b1a1a65e679997d1e3deff3 | |
parent | c3b73cbeb8c1f5588b0f516264ae34778975e6d6 (diff) | |
download | lua-0810bc707f98f05a2d598e6a00cb33280d16cf89.tar.gz lua-0810bc707f98f05a2d598e6a00cb33280d16cf89.tar.bz2 lua-0810bc707f98f05a2d598e6a00cb33280d16cf89.zip |
new syntax: |label|
-rw-r--r-- | lparser.c | 143 |
1 files changed, 94 insertions, 49 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lparser.c,v 1.78 2000/04/07 13:13:11 roberto Exp roberto $ | 2 | ** $Id: lparser.c,v 1.79 2000/04/07 19:35:20 roberto Exp roberto $ |
3 | ** LL(1) Parser and code generator for Lua | 3 | ** LL(1) Parser and code generator for Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -36,6 +36,7 @@ typedef struct Constdesc { | |||
36 | 36 | ||
37 | typedef struct Breaklabel { | 37 | typedef struct Breaklabel { |
38 | struct Breaklabel *previous; /* chain */ | 38 | struct Breaklabel *previous; /* chain */ |
39 | TString *label; | ||
39 | int breaklist; | 40 | int breaklist; |
40 | int stacklevel; | 41 | int stacklevel; |
41 | } Breaklabel; | 42 | } Breaklabel; |
@@ -171,6 +172,14 @@ static TString *str_checkname (LexState *ls) { | |||
171 | } | 172 | } |
172 | 173 | ||
173 | 174 | ||
175 | static TString *optionalname (LexState *ls) { | ||
176 | if (ls->token == TK_NAME) | ||
177 | return str_checkname(ls); | ||
178 | else | ||
179 | return NULL; | ||
180 | } | ||
181 | |||
182 | |||
174 | static void luaI_registerlocalvar (LexState *ls, TString *varname, | 183 | static void luaI_registerlocalvar (LexState *ls, TString *varname, |
175 | int line) { | 184 | int line) { |
176 | FuncState *fs = ls->fs; | 185 | FuncState *fs = ls->fs; |
@@ -317,6 +326,7 @@ static int getvarname (LexState *ls, expdesc *var) { | |||
317 | 326 | ||
318 | static void enterbreak (FuncState *fs, Breaklabel *bl) { | 327 | static void enterbreak (FuncState *fs, Breaklabel *bl) { |
319 | bl->stacklevel = fs->stacklevel; | 328 | bl->stacklevel = fs->stacklevel; |
329 | bl->label = NULL; | ||
320 | bl->breaklist = NO_JUMP; | 330 | bl->breaklist = NO_JUMP; |
321 | bl->previous = fs->bl; | 331 | bl->previous = fs->bl; |
322 | fs->bl = bl; | 332 | fs->bl = bl; |
@@ -330,6 +340,20 @@ static void leavebreak (FuncState *fs, Breaklabel *bl) { | |||
330 | } | 340 | } |
331 | 341 | ||
332 | 342 | ||
343 | static Breaklabel *findlabel (FuncState *fs, TString *name) { | ||
344 | Breaklabel *bl; | ||
345 | for (bl=fs->bl; bl; bl=bl->previous) { | ||
346 | if (bl->label == name) | ||
347 | return bl; | ||
348 | } | ||
349 | if (name) /* label not found: choose appropriate error message */ | ||
350 | luaX_syntaxerror(fs->ls, "break not inside given label", name->str); | ||
351 | else | ||
352 | luaK_error(fs->ls, "break not inside while or repeat loop"); | ||
353 | return NULL; /* to avoid warnings */ | ||
354 | } | ||
355 | |||
356 | |||
333 | static void func_onstack (LexState *ls, FuncState *func) { | 357 | static void func_onstack (LexState *ls, FuncState *func) { |
334 | FuncState *fs = ls->fs; | 358 | FuncState *fs = ls->fs; |
335 | Proto *f = fs->f; | 359 | Proto *f = fs->f; |
@@ -419,7 +443,7 @@ static int explist1 (LexState *ls) { | |||
419 | expr(ls, &v); | 443 | expr(ls, &v); |
420 | n++; | 444 | n++; |
421 | } | 445 | } |
422 | luaK_tostack(ls, &v, 0); | 446 | luaK_tostack(ls, &v, 0); /* keep open number of values of last expression */ |
423 | return n; | 447 | return n; |
424 | } | 448 | } |
425 | 449 | ||
@@ -427,12 +451,12 @@ static int explist1 (LexState *ls) { | |||
427 | static int explist (LexState *ls) { | 451 | static int explist (LexState *ls) { |
428 | /* explist -> [ explist1 ] */ | 452 | /* explist -> [ explist1 ] */ |
429 | switch (ls->token) { | 453 | switch (ls->token) { |
430 | case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_UNTIL: | 454 | case TK_NUMBER: case TK_STRING: case TK_NIL: case '{': |
431 | case TK_EOS: case ';': case ')': | 455 | case TK_FUNCTION: case '(': case TK_NAME: case '%': |
432 | return 0; /* empty list */ | 456 | case TK_NOT: case '-': /* first `expr' */ |
433 | |||
434 | default: | ||
435 | return explist1(ls); | 457 | return explist1(ls); |
458 | default: | ||
459 | return 0; /* empty list */ | ||
436 | } | 460 | } |
437 | } | 461 | } |
438 | 462 | ||
@@ -998,44 +1022,73 @@ static void namestat (LexState *ls) { | |||
998 | } | 1022 | } |
999 | 1023 | ||
1000 | 1024 | ||
1025 | static void retstat (LexState *ls) { | ||
1026 | /* stat -> RETURN explist */ | ||
1027 | FuncState *fs = ls->fs; | ||
1028 | setline_and_next(ls); /* skip RETURN */ | ||
1029 | explist(ls); | ||
1030 | luaK_code1(fs, OP_RETURN, ls->fs->nlocalvar); | ||
1031 | fs->stacklevel = fs->nlocalvar; /* removes all temp values */ | ||
1032 | } | ||
1033 | |||
1034 | |||
1035 | static void breakstat (LexState *ls) { | ||
1036 | /* stat -> BREAK [NAME] */ | ||
1037 | FuncState *fs = ls->fs; | ||
1038 | Breaklabel *bl; | ||
1039 | int currentlevel = fs->stacklevel; | ||
1040 | setline_and_next(ls); /* skip BREAK */ | ||
1041 | bl = findlabel(fs, optionalname(ls)); | ||
1042 | luaK_adjuststack(fs, currentlevel - bl->stacklevel); | ||
1043 | luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); | ||
1044 | fs->stacklevel = currentlevel; | ||
1045 | } | ||
1046 | |||
1047 | |||
1001 | static int stat (LexState *ls) { | 1048 | static int stat (LexState *ls) { |
1002 | int line = ls->linenumber; /* may be needed for error messages */ | 1049 | int line = ls->linenumber; /* may be needed for error messages */ |
1003 | switch (ls->token) { | 1050 | switch (ls->token) { |
1004 | case TK_IF: /* stat -> ifstat */ | 1051 | case TK_IF: /* stat -> ifstat */ |
1005 | ifstat(ls, line); | 1052 | ifstat(ls, line); |
1006 | break; | 1053 | return 1; |
1007 | 1054 | ||
1008 | case TK_WHILE: /* stat -> whilestat */ | 1055 | case TK_WHILE: /* stat -> whilestat */ |
1009 | whilestat(ls, line); | 1056 | whilestat(ls, line); |
1010 | break; | 1057 | return 1; |
1011 | 1058 | ||
1012 | case TK_DO: { /* stat -> DO block END */ | 1059 | case TK_DO: /* stat -> DO block END */ |
1013 | setline_and_next(ls); /* skip DO */ | 1060 | setline_and_next(ls); /* skip DO */ |
1014 | block(ls); | 1061 | block(ls); |
1015 | check_END(ls, TK_DO, line); | 1062 | check_END(ls, TK_DO, line); |
1016 | break; | 1063 | return 1; |
1017 | } | ||
1018 | 1064 | ||
1019 | case TK_REPEAT: /* stat -> repeatstat */ | 1065 | case TK_REPEAT: /* stat -> repeatstat */ |
1020 | repeatstat(ls, line); | 1066 | repeatstat(ls, line); |
1021 | break; | 1067 | return 1; |
1022 | 1068 | ||
1023 | case TK_FUNCTION: /* stat -> funcstat */ | 1069 | case TK_FUNCTION: /* stat -> funcstat */ |
1024 | funcstat(ls, line); | 1070 | funcstat(ls, line); |
1025 | break; | 1071 | return 1; |
1026 | 1072 | ||
1027 | case TK_LOCAL: /* stat -> localstat */ | 1073 | case TK_LOCAL: /* stat -> localstat */ |
1028 | localstat(ls); | 1074 | localstat(ls); |
1029 | break; | 1075 | return 1; |
1030 | 1076 | ||
1031 | case TK_NAME: case '%': /* stat -> namestat */ | 1077 | case TK_NAME: case '%': /* stat -> namestat */ |
1032 | namestat(ls); | 1078 | namestat(ls); |
1033 | break; | 1079 | return 1; |
1080 | |||
1081 | case TK_RETURN: /* stat -> retstat */ | ||
1082 | retstat(ls); | ||
1083 | return 2; /* must be last statement */ | ||
1084 | |||
1085 | case TK_BREAK: /* stat -> breakstat */ | ||
1086 | breakstat(ls); | ||
1087 | return 2; /* must be last statement */ | ||
1034 | 1088 | ||
1035 | default: | 1089 | default: |
1036 | return 0; /* no statement */ | 1090 | return 0; /* no statement */ |
1037 | } | 1091 | } |
1038 | return 1; | ||
1039 | } | 1092 | } |
1040 | 1093 | ||
1041 | 1094 | ||
@@ -1092,44 +1145,36 @@ static void body (LexState *ls, int needself, int line) { | |||
1092 | } | 1145 | } |
1093 | 1146 | ||
1094 | 1147 | ||
1095 | static void ret (LexState *ls) { | 1148 | /* }====================================================================== */ |
1096 | /* ret -> [RETURN explist sc | BREAK sc] */ | 1149 | |
1097 | FuncState *fs = ls->fs; | 1150 | |
1098 | switch (ls->token) { | 1151 | static void label (LexState *ls, Breaklabel *bl) { |
1099 | case TK_RETURN: { | 1152 | /* label -> [ '|' NAME '|' ] */ |
1100 | setline_and_next(ls); /* skip RETURN */ | 1153 | if (optional(ls, '|')) { |
1101 | explist(ls); | 1154 | enterbreak(ls->fs, bl); |
1102 | luaK_code1(fs, OP_RETURN, ls->fs->nlocalvar); | 1155 | bl->label = str_checkname(ls); |
1103 | fs->stacklevel = fs->nlocalvar; /* removes all temp values */ | 1156 | check(ls, '|'); |
1104 | optional(ls, ';'); | ||
1105 | break; | ||
1106 | } | ||
1107 | case TK_BREAK: { | ||
1108 | Breaklabel *bl = fs->bl; | ||
1109 | int currentlevel = fs->stacklevel; | ||
1110 | if (bl == NULL) | ||
1111 | luaK_error(ls, "break not inside while or repeat loop"); | ||
1112 | |||
1113 | setline_and_next(ls); /* skip BREAK */ | ||
1114 | luaK_adjuststack(fs, currentlevel - bl->stacklevel); | ||
1115 | luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); | ||
1116 | optional(ls, ';'); | ||
1117 | fs->stacklevel = currentlevel; | ||
1118 | break; | ||
1119 | } | ||
1120 | } | 1157 | } |
1158 | else | ||
1159 | bl->label = NULL; /* there is no label */ | ||
1121 | } | 1160 | } |
1122 | 1161 | ||
1123 | /* }====================================================================== */ | ||
1124 | |||
1125 | 1162 | ||
1126 | static void chunk (LexState *ls) { | 1163 | static void chunk (LexState *ls) { |
1127 | /* chunk -> { stat [;] } ret */ | 1164 | /* chunk -> { [label] stat [';'] } */ |
1128 | while (stat(ls)) { | 1165 | Breaklabel bl; |
1166 | int a; | ||
1167 | do { | ||
1168 | label(ls, &bl); | ||
1169 | a = stat(ls); | ||
1170 | if (a != 0) | ||
1171 | optional(ls, ';'); | ||
1172 | else if (bl.label) | ||
1173 | luaK_error(ls, "label without a statement"); | ||
1129 | LUA_ASSERT(ls->L, ls->fs->stacklevel == ls->fs->nlocalvar, | 1174 | LUA_ASSERT(ls->L, ls->fs->stacklevel == ls->fs->nlocalvar, |
1130 | "stack size != # local vars"); | 1175 | "stack size != # local vars"); |
1131 | optional(ls, ';'); | 1176 | if (bl.label) |
1132 | } | 1177 | leavebreak(ls->fs, &bl); |
1133 | ret(ls); /* optional return */ | 1178 | } while (a == 1); |
1134 | } | 1179 | } |
1135 | 1180 | ||