Browse Source

BUG: did not handle properly pragmas $endinput/$debug inside a $if.

Roberto Ierusalimschy 28 years ago
parent
commit
33f4fef410
1 changed files with 44 additions and 36 deletions
  1. 44 36
      lex.c

+ 44 - 36
lex.c

@@ -1,4 +1,4 @@
-char *rcs_lex = "$Id: lex.c,v 3.2 1997/04/14 15:30:29 roberto Exp roberto $";
+char *rcs_lex = "$Id: lex.c,v 3.4 1997/06/11 14:20:51 roberto Exp $";
 
 
 #include <ctype.h>
@@ -23,17 +23,17 @@ char *rcs_lex = "$Id: lex.c,v 3.2 1997/04/14 15:30:29 roberto Exp roberto $";
 static int current;  /* look ahead character */
 static Input input;  /* input function */
 
-#define MAX_IFS	10
 
-/* "ifstate" keeps the state of each nested $if the lexical is
-** dealing with. The first bit indicates whether the $if condition
-** is false or true. The second bit indicates whether the lexical is
-** inside the "then" part (0) or the "else" part (2)
-*/
-static int ifstate[MAX_IFS];  /* 0 => then part - condition false */
-                              /* 1 => then part - condition true */
-                              /* 2 => else part - condition false */
-                              /* 3 => else part - condition true */
+#define MAX_IFS	5
+
+/* "ifstate" keeps the state of each nested $if the lexical is dealing with. */
+
+static struct {
+  int elsepart;  /* true if its in the $else part */
+  int condition;  /* true if $if condition is true */
+  int skip;  /* true if part must be skiped */
+} ifstate[MAX_IFS];
+
 static int iflevel;  /* level of nested $if's */
 
 
@@ -42,6 +42,8 @@ void lua_setinput (Input fn)
   current = '\n';
   lua_linenumber = 0;
   iflevel = 0;
+  ifstate[0].skip = 0;
+  ifstate[0].elsepart = 1;  /* to avoid a free $else */
   input = fn;
 }
 
@@ -117,10 +119,9 @@ static void skipspace (void)
 
 static int checkcond (char *buff)
 {
-  if (strcmp(buff, "nil") == 0)
-    return 0;
-  else if (strcmp(buff, "1") == 0)
-    return 1;
+  static char *opts[] = {"nil", "1"};
+  int i = luaI_findstring(buff, opts); 
+  if (i >= 0) return i;
   else if (isalpha((unsigned char)buff[0]) || buff[0] == '_')
     return luaI_globaldefined(buff);
   else {
@@ -149,11 +150,9 @@ static void readname (char *buff)
 static void inclinenumber (void);
 
 
-static void ifskip (int thisiflevel)
+static void ifskip (void)
 {
-  if (thisiflevel < 0) return;
-  while (iflevel > thisiflevel &&
-         (ifstate[thisiflevel] == 0 || ifstate[thisiflevel] == 3)) {
+  while (ifstate[iflevel].skip) {
     if (current == '\n')
       inclinenumber();
     else if (current == 0)
@@ -166,51 +165,60 @@ static void ifskip (int thisiflevel)
 static void inclinenumber (void)
 {
   static char *pragmas [] = 
-    {"debug", "nodebug", "end", "ifnot", "if", "else", "endinput", NULL};
+    {"debug", "nodebug", "endinput", "end", "ifnot", "if", "else", NULL};
   next();  /* skip '\n' */
   ++lua_linenumber;
   if (current == '$') {  /* is a pragma? */
     char buff[PRAGMASIZE+1];
     int ifnot = 0;
+    int skip = ifstate[iflevel].skip;
     next();  /* skip $ */
     readname(buff);
     switch (luaI_findstring(buff, pragmas)) {
       case 0:  /* debug */
-        lua_debug = 1;
+        if (!skip) lua_debug = 1;
         break;
       case 1:  /* nodebug */
-        lua_debug = 0;
+        if (!skip) lua_debug = 0;
         break;
-      case 2:  /* end */
-        if (--iflevel < 0)
+      case 2:  /* endinput */
+        if (!skip) {
+          current = 0;
+          iflevel = 0;  /* to allow $endinput inside a $if */
+        }
+        break;
+      case 3:  /* end */
+        if (iflevel-- == 0)
           luaI_auxsyntaxerror("unmatched $endif");
         break;
-      case 3:  /* ifnot */
+      case 4:  /* ifnot */
         ifnot = 1;
         /* go through */
-      case 4:  /* if */
-        if (iflevel == MAX_IFS)
+      case 5:  /* if */
+        if (iflevel == MAX_IFS-1)
           luaI_auxsyntaxerror("too many nested `$ifs'");
         readname(buff);
-        ifstate[iflevel++] = checkcond(buff) ? !ifnot : ifnot;
+        iflevel++;
+        ifstate[iflevel].elsepart = 0;
+        ifstate[iflevel].condition = checkcond(buff) ? !ifnot : ifnot;
+        ifstate[iflevel].skip = skip || !ifstate[iflevel].condition;
         break;
-      case 5:  /* else */
-        if (iflevel <= 0 || (ifstate[iflevel-1] & 2))
+      case 6:  /* else */
+        if (ifstate[iflevel].elsepart)
           luaI_auxsyntaxerror("unmatched $else");
-        ifstate[iflevel-1] = ifstate[iflevel-1] | 2;
-        break;
-      case 6:  /* endinput */
-        current = 0;
+        ifstate[iflevel].elsepart = 1;
+        ifstate[iflevel].skip =
+                    ifstate[iflevel-1].skip || ifstate[iflevel].condition;
         break;
       default:
         luaI_auxsynterrbf("invalid pragma", buff);
     }
     skipspace();
-    if (current == '\n')  /* pragma must end with a '\n' */
+    if (current == '\n')  /* pragma must end with a '\n' ... */
       inclinenumber();
     else if (current != 0)  /* or eof */
       luaI_auxsyntaxerror("invalid pragma format");
-    ifskip(iflevel-1);
+    ifskip();
   }
 }