ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

llex.cpp

Go to the documentation of this file.
00001 /*
00002 ** Lexical Analizer
00003 ** See Copyright Notice in lua.h
00004 */
00005 
00006 #define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
00007 #define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
00008 
00009 #include "common/util.h"
00010 
00011 #include "engines/grim/lua/lauxlib.h"
00012 #include "engines/grim/lua/llex.h"
00013 #include "engines/grim/lua/lmem.h"
00014 #include "engines/grim/lua/lobject.h"
00015 #include "engines/grim/lua/lparser.h"
00016 #include "engines/grim/lua/lstate.h"
00017 #include "engines/grim/lua/lstring.h"
00018 #include "engines/grim/lua/lstx.h"
00019 #include "engines/grim/lua/luadebug.h"
00020 #include "engines/grim/lua/lzio.h"
00021 
00022 namespace Grim {
00023 
00024 int32 lua_debug = 0;
00025 
00026 #define next(LS)            (LS->current = zgetc(LS->lex_z))
00027 
00028 static struct {
00029     const char *name;
00030     int token;
00031 } reserved [] = {
00032     {"and", AND}, {"do", DO}, {"else", ELSE}, {"elseif", ELSEIF},
00033     {"end", END}, {"function", FUNCTION}, {"if", IF}, {"local", LOCAL},
00034     {"nil", NIL}, {"not", NOT}, {"or", OR}, {"repeat", REPEAT},
00035     {"return", RETURN}, {"then", THEN}, {"until", UNTIL}, {"while", WHILE}
00036 };
00037 
00038 void luaX_init() {
00039     uint32 i;
00040     for (i = 0; i < (sizeof(reserved) / sizeof(reserved[0])); i++) {
00041         TaggedString *ts = luaS_new(reserved[i].name);
00042         ts->head.marked = reserved[i].token;  /* reserved word  (always > 255) */
00043     }
00044 }
00045 
00046 static void firstline(LexState *LS) {
00047     int32 c = zgetc(LS->lex_z);
00048     if (c == '#') {
00049         LS->linenumber++;
00050         while ((c = zgetc(LS->lex_z)) != '\n' && c != EOZ) ; // skip first line
00051     }
00052     zungetc(LS->lex_z);
00053 }
00054 
00055 void luaX_setinput(ZIO *z) {
00056     LexState *LS = lua_state->lexstate;
00057     LS->current = '\n';
00058     LS->linelasttoken = 0;
00059     LS->linenumber = 0;
00060     LS->iflevel = 0;
00061     LS->ifstate[0].skip = 0;
00062     LS->ifstate[0].elsepart = 1;  // to avoid a free $else
00063     LS->lex_z = z;
00064     firstline(LS);
00065     luaL_resetbuffer();
00066 }
00067 
00068 /*
00069 ** =======================================================
00070 ** PRAGMAS
00071 ** =======================================================
00072 */
00073 
00074 #define PRAGMASIZE  20
00075 
00076 static void skipspace(LexState *LS) {
00077     while (LS->current == ' ' || LS->current == '\t' || LS->current == '\r')
00078         next(LS);
00079 }
00080 
00081 static int32 checkcond(char *buff) {
00082     static const char *opts[] = { "nil", "1", nullptr };
00083     int32 i = luaO_findstring(buff, opts);
00084     if (i >= 0)
00085         return i;
00086     else if (Common::isAlpha((byte)buff[0]) || buff[0] == '_')
00087         return luaS_globaldefined(buff);
00088     else {
00089         luaY_syntaxerror("invalid $if condition", buff);
00090         return 0;  // to avoid warnings
00091     }
00092 }
00093 
00094 static void readname(LexState *LS, char *buff) {
00095     int32 i = 0;
00096     skipspace(LS);
00097     while (Common::isAlnum(LS->current) || LS->current == '_') {
00098         if (i >= PRAGMASIZE) {
00099             buff[PRAGMASIZE] = 0;
00100             luaY_syntaxerror("pragma too long", buff);
00101         }
00102         buff[i++] = LS->current;
00103         next(LS);
00104     }
00105     buff[i] = 0;
00106 }
00107 
00108 static void inclinenumber (LexState *LS);
00109 
00110 static void ifskip (LexState *LS) {
00111     while (LS->ifstate[LS->iflevel].skip) {
00112         if (LS->current == '\n')
00113             inclinenumber(LS);
00114         else if (LS->current == EOZ)
00115             luaY_syntaxerror("input ends inside a $if", "");
00116         else
00117             next(LS);
00118     }
00119 }
00120 
00121 static void inclinenumber (LexState *LS) {
00122     static const char *pragmas [] =
00123     { "debug", "nodebug", "endinput", "end", "ifnot", "if", "else", nullptr };
00124     next(LS);  // skip '\n'
00125     ++LS->linenumber;
00126     if (LS->current == '$') {  // is a pragma?
00127         char buff[PRAGMASIZE + 1];
00128         int32 ifnot = 0;
00129         int32 skip = LS->ifstate[LS->iflevel].skip;
00130         next(LS);  // skip $
00131         readname(LS, buff);
00132         switch (luaO_findstring(buff, pragmas)) {
00133         case 0:  // debug
00134             if (!skip)
00135                 lua_debug = 1;
00136             break;
00137         case 1:  // nodebug
00138             if (!skip)
00139                 lua_debug = 0;
00140             break;
00141         case 2:  // endinput
00142             if (!skip) {
00143                 LS->current = EOZ;
00144                 LS->iflevel = 0;  // to allow $endinput inside a $if
00145             }
00146             break;
00147         case 3:  // end
00148             if (LS->iflevel-- == 0)
00149                 luaY_syntaxerror("unmatched $end", "$end");
00150             break;
00151         case 4:  // ifnot
00152             ifnot = 1;
00153             // fall through
00154         case 5:  // if
00155             if (LS->iflevel == MAX_IFS - 1)
00156                 luaY_syntaxerror("too many nested $ifs", "$if");
00157             readname(LS, buff);
00158             LS->iflevel++;
00159             LS->ifstate[LS->iflevel].elsepart = 0;
00160             LS->ifstate[LS->iflevel].condition = checkcond(buff) ? !ifnot : ifnot;
00161             LS->ifstate[LS->iflevel].skip = skip || !LS->ifstate[LS->iflevel].condition;
00162             break;
00163         case 6:  // else
00164             if (LS->ifstate[LS->iflevel].elsepart)
00165                 luaY_syntaxerror("unmatched $else", "$else");
00166             LS->ifstate[LS->iflevel].elsepart = 1;
00167             LS->ifstate[LS->iflevel].skip = LS->ifstate[LS->iflevel - 1].skip || LS->ifstate[LS->iflevel].condition;
00168             break;
00169         default:
00170             luaY_syntaxerror("unknown pragma", buff);
00171         }
00172         skipspace(LS);
00173         if (LS->current == '\n')  // pragma must end with a '\n' ...
00174             inclinenumber(LS);
00175         else if (LS->current != EOZ)  // or eof
00176             luaY_syntaxerror("invalid pragma format", buff);
00177         ifskip(LS);
00178     }
00179 }
00180 
00181 /*
00182 ** =======================================================
00183 ** LEXICAL ANALIZER
00184 ** =======================================================
00185 */
00186 
00187 #define save(c)             luaL_addchar(c)
00188 #define save_and_next(LS)   (save(LS->current), next(LS))
00189 
00190 
00191 char *luaX_lasttoken() {
00192     save(0);
00193     return luaL_buffer();
00194 }
00195 
00196 static int read_long_string(LexState *LS, YYSTYPE *l) {
00197     int cont = 0;
00198     while (1) {
00199         switch (LS->current) {
00200         case EOZ:
00201             save(0);
00202             return WRONGTOKEN;
00203         case '[':
00204             save_and_next(LS);
00205             if (LS->current == '[') {
00206                 cont++;
00207                 save_and_next(LS);
00208             }
00209             continue;
00210         case ']':
00211             save_and_next(LS);
00212             if (LS->current == ']') {
00213                 if (cont == 0)
00214                     goto endloop;
00215                 cont--;
00216                 save_and_next(LS);
00217             }
00218             continue;
00219         case '\n':
00220             save('\n');
00221             inclinenumber(LS);
00222             continue;
00223         default:
00224             save_and_next(LS);
00225         }
00226     }
00227 endloop:
00228     save_and_next(LS);  // pass the second ']'
00229     Mbuffer[Mbuffnext - 2] = 0;  // erases ']]'
00230     l->pTStr = luaS_new(Mbuffbase + 2);
00231     Mbuffer[Mbuffnext - 2] = ']';  // restores ']]'
00232     return STRING;
00233 }
00234 
00235 /* to avoid warnings; this declaration cannot be public since YYSTYPE
00236 ** cannot be visible in llex.h (otherwise there is an error, since
00237 ** the parser body redefines it!)
00238 */
00239 int32 luaY_lex(YYSTYPE *l);
00240 int32 luaY_lex(YYSTYPE *l) {
00241     LexState *LS = lua_state->lexstate;
00242     double a;
00243     luaL_resetbuffer();
00244     if (lua_debug)
00245         luaY_codedebugline(LS->linelasttoken);
00246     LS->linelasttoken = LS->linenumber;
00247     while (1) {
00248         switch (LS->current) {
00249         case ' ':
00250         case '\t':
00251         case '\r':  // CR: to avoid problems with DOS
00252             next(LS);
00253             continue;
00254         case '\n':
00255             inclinenumber(LS);
00256             LS->linelasttoken = LS->linenumber;
00257             continue;
00258         case '-':
00259             save_and_next(LS);
00260             if (LS->current != '-')
00261                 return '-';
00262             do {
00263                 next(LS);
00264             } while (LS->current != '\n' && LS->current != EOZ);
00265             luaL_resetbuffer();
00266             continue;
00267         case '[':
00268             save_and_next(LS);
00269             if (LS->current != '[')
00270                 return '[';
00271             else {
00272                 save_and_next(LS);  // pass the second '['
00273                 return read_long_string(LS, l);
00274             }
00275         case '=':
00276             save_and_next(LS);
00277             if (LS->current != '=')
00278                 return '=';
00279             else {
00280                 save_and_next(LS);
00281                 return EQ;
00282             }
00283         case '<':
00284             save_and_next(LS);
00285             if (LS->current != '=')
00286                 return '<';
00287             else {
00288                 save_and_next(LS);
00289                 return LE;
00290             }
00291         case '>':
00292             save_and_next(LS);
00293             if (LS->current != '=')
00294                 return '>';
00295             else {
00296                 save_and_next(LS);
00297                 return GE;
00298             }
00299         case '~':
00300             save_and_next(LS);
00301             if (LS->current != '=')
00302                 return '~';
00303             else {
00304                 save_and_next(LS);
00305                 return NE;
00306             }
00307         case '"':
00308         case '\'':
00309             {
00310                 int32 del = LS->current;
00311                 save_and_next(LS);
00312                 while (LS->current != del) {
00313                     switch (LS->current) {
00314                     case EOZ:
00315                     case '\n':
00316                         save(0);
00317                         return WRONGTOKEN;
00318                     case '\\':
00319                         next(LS);  // do not save the '\'
00320                         switch (LS->current) {
00321                         case 'n':
00322                             save('\n');
00323                             next(LS);
00324                             break;
00325                         case 't':
00326                             save('\t');
00327                             next(LS);
00328                             break;
00329                         case 'r':
00330                             save('\r');
00331                             next(LS);
00332                             break;
00333                         case '\n':
00334                             save('\n');
00335                             inclinenumber(LS);
00336                             break;
00337                         default :
00338                             save_and_next(LS); break;
00339                         }
00340                         break;
00341                     default:
00342                         save_and_next(LS);
00343                     }
00344                 }
00345                 next(LS);  // skip delimiter
00346                 save(0);
00347                 l->pTStr = luaS_new(Mbuffbase + 1);
00348                 Mbuffer[Mbuffnext - 1] = del;  // restore delimiter
00349                 return STRING;
00350             }
00351         case '.':
00352             save_and_next(LS);
00353             if (LS->current == '.') {
00354                 save_and_next(LS);
00355                 if (LS->current == '.') {
00356                     save_and_next(LS);
00357                     return DOTS;   // ...
00358                 } else
00359                     return CONC;   // ..
00360                 } else if (!Common::isDigit(LS->current))
00361                     return '.';
00362                 // LS->current is a digit: goes through to number/
00363                 a = 0.0;
00364                 goto fraction;
00365         case '0':
00366         case '1':
00367         case '2':
00368         case '3':
00369         case '4':
00370         case '5':
00371         case '6':
00372         case '7':
00373         case '8':
00374         case '9':
00375             a = 0.0;
00376             do {
00377                 a = 10.0 * a + (LS->current - '0');
00378                 save_and_next(LS);
00379             } while (Common::isDigit(LS->current));
00380             if (LS->current == '.') {
00381                 save_and_next(LS);
00382                 if (LS->current == '.') {
00383                     save(0);
00384                     luaY_error("ambiguous syntax (decimal point x string concatenation)");
00385                 }
00386             }
00387 fraction:
00388             {
00389                 double da = 0.1;
00390                 while (Common::isDigit(LS->current)) {
00391                     a += (LS->current - '0') * da;
00392                     da /= 10.0;
00393                     save_and_next(LS);
00394                 }
00395                 if (toupper(LS->current) == 'E') {
00396                     int32 e = 0;
00397                     int32 neg;
00398                     double ea;
00399                     save_and_next(LS);
00400                     neg = (LS->current == '-');
00401                     if (LS->current == '+' || LS->current == '-')
00402                         save_and_next(LS);
00403                     if (!Common::isDigit(LS->current)) {
00404                         save(0);
00405                         return WRONGTOKEN;
00406                     }
00407                     do {
00408                         e = 10 * e + (LS->current - '0');
00409                         save_and_next(LS);
00410                     } while (Common::isDigit(LS->current));
00411                     for (ea = neg ? 0.1 : 10.0; e > 0; e >>= 1) {
00412                         if (e & 1)
00413                             a *= ea;
00414                         ea *= ea;
00415                     }
00416                 }
00417                 l->vReal = a;
00418                 return NUMBER;
00419             }
00420         case EOZ:
00421             save(0);
00422             if (LS->iflevel > 0)
00423                 luaY_syntaxerror("input ends inside a $if", "");
00424             return 0;
00425         default:
00426             if (LS->current != '_' && !Common::isAlpha(LS->current)) {
00427                 int32 c = LS->current;
00428                 save_and_next(LS);
00429                 return c;
00430             } else {  // identifier or reserved word
00431                 TaggedString *ts;
00432                 do {
00433                     save_and_next(LS);
00434                 } while (Common::isAlnum(LS->current) || LS->current == '_');
00435                 save(0);
00436                 ts = luaS_new(Mbuffbase);
00437                 if (ts->head.marked >= 255)
00438                     return ts->head.marked;  // reserved word
00439                 l->pTStr = ts;
00440                 return NAME;
00441             }
00442         }
00443     }
00444 }
00445 
00446 } // end of namespace Grim


Generated on Sat Oct 19 2019 05:01:04 for ResidualVM by doxygen 1.7.1
curved edge   curved edge