Make parser and scanner reentrant
authorRan Benita <ran234@gmail.com>
Tue, 27 Mar 2012 21:41:22 +0000 (22:41 +0100)
committerDaniel Stone <daniel@fooishbar.org>
Tue, 27 Mar 2012 21:41:22 +0000 (22:41 +0100)
All global state is removed from the parser and scanner.
This makes use of the standard facilities in Bison and Flex for
reentrant/pure scanner/lexer and location tracking.

Signed-off-by: Ran Benita <ran234@gmail.com>
[daniels: Updated to current sources.]

src/xkbcomp/misc.c
src/xkbcomp/parseutils.c
src/xkbcomp/parseutils.h
src/xkbcomp/xkbcomp.c
src/xkbcomp/xkbcomp.h
src/xkbcomp/xkbparse.y
src/xkbcomp/xkbscan.l

index 5c9c13a..7bb05a5 100644 (file)
@@ -56,8 +56,6 @@ ProcessIncludeFile(struct xkb_context *context,
 {
     FILE *file;
     XkbFile *rtrn, *mapToUse, *next;
-    char oldFile[1024] = {0};
-    int oldLine = lineNum;
 
     file = XkbFindFileInPath(context, stmt->file, file_type, &stmt->path);
     if (file == NULL)
@@ -66,16 +64,9 @@ ProcessIncludeFile(struct xkb_context *context,
                 XkbDirectoryForInclude(file_type));
         return False;
     }
-    if (scanFile)
-        strcpy(oldFile, scanFile);
-    else
-        memset(oldFile, 0, sizeof(oldFile));
-    oldLine = lineNum;
-    setScanState(stmt->file, 1);
     /* parse the file */
-    if ((XKBParseFile(file, &rtrn) == 0) || (rtrn == NULL))
+    if ((XKBParseFile(file, stmt->file, &rtrn) == 0) || (rtrn == NULL))
     {
-        setScanState(oldFile, oldLine);
         ERROR("Error interpreting include file \"%s\"\n", stmt->file);
         fclose(file);
         return False;
@@ -114,7 +105,6 @@ ProcessIncludeFile(struct xkb_context *context,
               stmt->file);
         ACTION("Using first defined map, \"%s\"\n", rtrn->name);
     }
-    setScanState(oldFile, oldLine);
     if (mapToUse->type != file_type)
     {
         ERROR("Include file wrong type (expected %s, got %s)\n",
index 1d66986..1392514 100644 (file)
@@ -552,7 +552,7 @@ PrintStmtAddrs(ParseCommon * stmt)
 #endif
 
 void
-CheckDefaultMap(XkbFile * maps)
+CheckDefaultMap(XkbFile * maps, const char *fileName)
 {
     XkbFile *dflt, *tmp;
 
@@ -569,7 +569,7 @@ CheckDefaultMap(XkbFile * maps)
                 if (warningLevel > 2)
                 {
                     WARN("Multiple default components in %s\n",
-                          (scanFile ? scanFile : "(unknown)"));
+                          (fileName ? fileName : "(unknown)"));
                     ACTION("Using %s, ignoring %s\n",
                             (dflt->name ? dflt->name : "(first)"),
                             (tmp->name ? tmp->name : "(subsequent)"));
@@ -603,11 +603,11 @@ CreateXKBFile(int type, char *name, ParseCommon * defs, unsigned flags)
 }
 
 unsigned
-StmtSetMerge(ParseCommon * stmt, unsigned merge)
+StmtSetMerge(ParseCommon * stmt, unsigned merge, YYLTYPE *loc, void *scanner)
 {
     if ((merge == MergeAltForm) && (stmt->stmtType != StmtKeycodeDef))
     {
-        yyerror("illegal use of 'alternate' merge mode");
+        yyerror(loc, scanner, "illegal use of 'alternate' merge mode");
         merge = MergeDefault;
     }
     return merge;
index 89458df..1e7ac65 100644 (file)
 #define        XKBPARSE_H 1
 
 #include "xkbcomp.h"
+#include "xkbparse.h"
 
-extern char scanBuf[1024];
-extern int scanInt;
-extern unsigned long scanULong;
-extern int lineNum;
+struct parser_param {
+    void *scanner;
+    XkbFile *rtrn;
+};
 
-extern XkbFile *rtrnValue;
+struct scanner_extra {
+    char *scanFile;
+    /* FIXME: This can overflow! */
+    char scanBuf[8192];
+    char *s;
+};
 
 extern ParseCommon *AppendStmt(ParseCommon * /* to */ ,
                                ParseCommon *    /* append */
@@ -123,7 +129,9 @@ extern IncludeStmt *IncludeCreate(char * /* str */ ,
     );
 
 extern unsigned StmtSetMerge(ParseCommon * /* stmt */ ,
-                             unsigned   /* merge */
+                             unsigned   /* merge */,
+                             YYLTYPE *  /* loc */,
+                             void *     /* scanner */
     );
 
 #ifdef DEBUG
@@ -132,12 +140,14 @@ extern void PrintStmtAddrs(ParseCommon *        /* stmt */
 #endif
 
 extern int XKBParseFile(FILE * /* file */ ,
+                        const char *    /* fileName */,
                         XkbFile **      /* pRtrn */
     );
 
-extern int XKBParseString(const char *string, XkbFile ** pRtrn);
+extern int XKBParseString(const char *string, const char *fileName,
+                          XkbFile ** pRtrn);
 
-extern void CheckDefaultMap(XkbFile * maps);
+extern void CheckDefaultMap(XkbFile * maps, const char *fileName);
 
 extern XkbFile *CreateXKBFile(int /* type */ ,
                               char * /* name */ ,
@@ -147,14 +157,9 @@ extern XkbFile *CreateXKBFile(int /* type */ ,
 
 extern void FreeXKBFile(XkbFile *file);
 
-extern void yyerror(const char *        /* msg */
-    );
-
-extern void setScanState(const char * /* file */ ,
-                         int     /* line */
-    );
-
 extern void FreeStmt(ParseCommon * /* stmt */
     );
 
+extern void yyerror(struct YYLTYPE *loc, void *scanner, const char *msg);
+
 #endif /* XKBPARSE_H */
index bf03626..051c51f 100644 (file)
@@ -212,7 +212,6 @@ compile_keymap(struct xkb_context *context, XkbFile *file)
 
 err:
     FreeXKBFile(file);
-    free(scanFile);
     XkbcFreeAllAtoms();
     return xkb;
 }
@@ -273,8 +272,7 @@ xkb_map_new_from_string(struct xkb_context *context,
         return NULL;
     }
 
-    setScanState("input", 1);
-    if (!XKBParseString(string, &file) || !file) {
+    if (!XKBParseString(string, "input", &file) || !file) {
         ERROR("failed to parse input xkb file\n");
         return NULL;
     }
@@ -306,8 +304,7 @@ xkb_map_new_from_fd(struct xkb_context *context,
         return NULL;
     }
 
-    setScanState("input", 1);
-    if (!XKBParseFile(fptr, &file) || !file) {
+    if (!XKBParseFile(fptr, "(unknown file)", &file) || !file) {
         ERROR("failed to parse input xkb file\n");
        return NULL;
     }
index 4a6212b..cdbc6ed 100644 (file)
@@ -33,8 +33,6 @@
 #include "XKBcommonint.h"
 #include "xkbmisc.h"
 
-extern char *scanFile;
-
 #define        TypeUnknown     0
 #define        TypeBoolean     1
 #define        TypeInt         2
index 9db7ee5..b6131e6 100644 (file)
 
  ********************************************************/
 
+%{
+#define DEBUG 1
+#ifdef DEBUG
+#define        YYDEBUG 1
+#endif
+#include "parseutils.h"
+#include "xkbmisc.h"
+#include <X11/keysym.h>
+#include <stdlib.h>
+
+extern int yylex(union YYSTYPE *val, struct YYLTYPE *loc, void *scanner);
+
+#define scanner param->scanner
+%}
+
+%define                api.pure
+%locations
+%lex-param     { void *scanner }
+%parse-param   { struct parser_param *param }
+
 %token
        END_OF_FILE     0
        ERROR_TOK       255
        KEYPAD_KEYS             75
        FUNCTION_KEYS           76
        ALTERNATE_GROUP         77
-%{
-#define DEBUG 1
-#ifdef DEBUG
-#define        YYDEBUG 1
-#endif
-#include "parseutils.h"
-#include "xkbmisc.h"
-#include <X11/keysym.h>
-#include <stdlib.h>
 
-extern int yylex(void);
-extern FILE *yyin;
-%}
 %right EQUALS
 %left  PLUS MINUS
 %left  TIMES DIVIDE
@@ -110,6 +118,7 @@ extern FILE *yyin;
 %union {
        int              ival;
        unsigned         uval;
+       int64_t          num;
        char            *str;
        Atom            sval;
        ParseCommon     *any;
@@ -128,6 +137,8 @@ extern FILE *yyin;
         void            *geom;
        XkbFile         *file;
 }
+%type <num>     INTEGER FLOAT
+%type <str>     IDENT KEYNAME STRING
 %type <ival>   Number Integer Float SignedNumber
 %type <uval>   XkbCompositeType FileType MergeMode OptMergeMode
 %type <uval>   DoodadType Flag Flags OptFlags KeyCode
@@ -154,11 +165,11 @@ extern FILE *yyin;
 %type <file>   XkbCompositeMap XkbCompMapList
 %%
 XkbFile                :       XkbCompMapList
-                       { $$= rtrnValue= $1; }
+                       { $$= param->rtrn= $1; }
                |       XkbMapConfigList
-                       { $$= rtrnValue= $1;  }
+                       { $$= param->rtrn= $1;  }
                |       XkbConfig
-                       { $$= rtrnValue= $1; }
+                       { $$= param->rtrn= $1; }
                ;
 
 XkbCompMapList :       XkbCompMapList XkbCompositeMap
@@ -254,57 +265,57 @@ DeclList  :       DeclList Decl
 
 Decl           :       OptMergeMode VarDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode VModDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode InterpretDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode KeyNameDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode KeyAliasDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode KeyTypeDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode SymbolsDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode ModMapDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode GroupCompatDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode IndicatorMapDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode IndicatorNameDecl
                        {
-                           $2->merge= StmtSetMerge(&$2->common,$1);
+                           $2->merge= StmtSetMerge(&$2->common,$1,&@1,scanner);
                            $$= &$2->common;
                        }
                |       OptMergeMode ShapeDecl
@@ -319,11 +330,12 @@ Decl              :       OptMergeMode VarDecl
                |       MergeMode STRING
                        {
                            if ($1==MergeAltForm) {
-                               yyerror("cannot use 'alternate' to include other maps");
-                               $$= &IncludeCreate(scanBuf,MergeDefault)->common;
+                               yyerror(&@1, scanner,
+                                        "cannot use 'alternate' to include other maps");
+                               $$= &IncludeCreate($2,MergeDefault)->common;
                            }
                            else {
-                               $$= &IncludeCreate(scanBuf,$1)->common;
+                               $$= &IncludeCreate($2,$1)->common;
                            }
                         }
                ;
@@ -713,7 +725,7 @@ KeySymList  :       KeySymList COMMA KeySym
                        { $$= CreateKeysymList($1); }
                ;
 
-KeySym         :       IDENT   { $$= strdup(scanBuf); }
+KeySym         :       IDENT   { $$= $1; }
                |       SECTION { $$= strdup("section"); }
                |       Integer         
                        {
@@ -733,32 +745,36 @@ SignedNumber      :       MINUS Number    { $$= -$2; }
                |       Number              { $$= $1; }
                ;
 
-Number         :       FLOAT           { $$= scanInt; }
-               |       INTEGER         { $$= scanInt*XkbGeomPtsPerMM; }
+Number         :       FLOAT           { $$= $1; }
+               |       INTEGER         { $$= $1*XkbGeomPtsPerMM; }
                ;
 
 Float          :       FLOAT           { $$= 0; }
                ;
 
-Integer                :       INTEGER         { $$= scanInt; }
+Integer                :       INTEGER         { $$= $1; }
                ;
 
-KeyCode         :       INTEGER         { $$= scanULong; }
+KeyCode         :       INTEGER         { $$= $1; }
                 ;
 
-KeyName                :       KEYNAME         { $$= strdup(scanBuf); }
+KeyName                :       KEYNAME         { $$= $1; }
                ;
 
-Ident          :       IDENT   { $$= xkb_intern_atom(scanBuf); }
+Ident          :       IDENT   { $$= xkb_intern_atom($1); free($1); }
                |       DEFAULT { $$= xkb_intern_atom("default"); }
                ;
 
-String         :       STRING  { $$= xkb_intern_atom(scanBuf); }
+String         :       STRING  { $$= xkb_intern_atom($1); free($1); }
                ;
 
 OptMapName     :       MapName { $$= $1; }
                |               { $$= NULL; }
                ;
 
-MapName                :       STRING  { $$= strdup(scanBuf); }
+MapName                :       STRING  { $$= $1; }
                ;
+
+%%
+
+#undef scanner
index 599a388..9e08a76 100644 (file)
 
 #include "utils.h"
 #include "parseutils.h"
-#include "xkbparse.h"
 
-char *scanFile = NULL;
-int lineNum = 0;
 
-int scanInt;
-unsigned long scanULong;
+extern int yyparse(struct parser_param *param);
 
-static char *s;
-char scanBuf[1024];
-
-extern int yyparse(void);
+#define YY_USER_ACTION {                \
+        yylloc->first_line = yylineno;  \
+        yylloc->last_line = yylineno;   \
+}
 
 %}
 
+%option reentrant
+%option extra-type="struct scanner_extra *"
+%option bison-bridge bison-locations
+%option never-interactive nounistd
 %option case-insensitive
 %option yylineno
 %option noyywrap
 %option never-interactive
+%option nowarn
 %option noinput
 %option nounput
 
@@ -60,11 +61,21 @@ extern int yyparse(void);
 "//"[^\n]*
 "#"[^\n]*
 
-\"                     s = scanBuf; BEGIN(S_STR);
-\<                     s = scanBuf; BEGIN(S_KEY);
+\"                     yyextra->s = yyextra->scanBuf; BEGIN(S_STR);
+\<                     yyextra->s = yyextra->scanBuf; BEGIN(S_KEY);
 
-<S_STR>\"              BEGIN(INITIAL); *s = '\0'; return STRING;
-<S_KEY>\>              BEGIN(INITIAL); *s = '\0'; return KEYNAME;
+<S_STR>\" {
+                       BEGIN(INITIAL);
+                       *yyextra->s = '\0';
+                       yylval->str = strdup(yyextra->scanBuf);
+                       return STRING;
+                   }
+<S_KEY>\> {
+                       BEGIN(INITIAL);
+                       *yyextra->s = '\0';
+                       yylval->str = strdup(yyextra->scanBuf);
+                       return KEYNAME;
+                   }
 
 <S_STR,S_KEY>\\[0-7]{1,3} {
                        /* octal escape sequence */
@@ -77,7 +88,7 @@ extern int yyparse(void);
                            return ERROR_TOK;
                        }
 
-                       *s++ = result;
+                       *yyextra->s++ = result;
                    }
 
 <S_STR,S_KEY>\\[0-9]+ {
@@ -85,15 +96,15 @@ extern int yyparse(void);
                        return ERROR_TOK;
                    }
 
-<S_STR,S_KEY>\\n       *s++ = '\n';
-<S_STR,S_KEY>\\t       *s++ = '\t';
-<S_STR,S_KEY>\\r       *s++ = '\r';
-<S_STR,S_KEY>\\b       *s++ = '\b';
-<S_STR,S_KEY>\\f       *s++ = '\f';
-<S_STR,S_KEY>\\v       *s++ = '\v';
-<S_STR,S_KEY>\\e       *s++ = '\033';
+<S_STR,S_KEY>\\n       *yyextra->s++ = '\n';
+<S_STR,S_KEY>\\t       *yyextra->s++ = '\t';
+<S_STR,S_KEY>\\r       *yyextra->s++ = '\r';
+<S_STR,S_KEY>\\b       *yyextra->s++ = '\b';
+<S_STR,S_KEY>\\f       *yyextra->s++ = '\f';
+<S_STR,S_KEY>\\v       *yyextra->s++ = '\v';
+<S_STR,S_KEY>\\e       *yyextra->s++ = '\033';
 
-<S_STR,S_KEY>.         *s++ = yytext[0];
+<S_STR,S_KEY>.         *yyextra->s++ = yytext[0];
 
 xkb_keymap             return XKB_KEYMAP;
 xkb_keycodes           return XKB_KEYCODES;
@@ -141,19 +152,18 @@ keypad_keys               return KEYPAD_KEYS;
 function_keys          return FUNCTION_KEYS;
 alternate_group                return ALTERNATE_GROUP;
 
-[a-zA-Z_][a-zA-Z_0-9]* memcpy(scanBuf, yytext, yyleng + 1); return IDENT;
+[a-zA-Z_][a-zA-Z_0-9]* yylval->str = strdup(yytext); return IDENT;
 
 0x[a-fA-F0-9]+         |
 [0-9]+                 {
                            char *end;
-                           scanInt = strtol(yytext, &end, 0);
-                            scanULong = strtoul(yytext, &end, 0);
+                           yylval->num = strtoul(yytext, &end, 0);
 
                            return INTEGER;
                        }
 [0-9]+\.[0-9]+ {
                            char *end;
-                           scanInt = strtod(yytext, &end) * XkbGeomPtsPerMM;
+                           yylval->num = strtod(yytext, &end) * XkbGeomPtsPerMM;
 
                            return FLOAT;
                        }
@@ -184,62 +194,75 @@ alternate_group           return ALTERNATE_GROUP;
 %%
 
 void
-yyerror(const char *msg)
+yyerror(YYLTYPE *loc, void *scanner, const char *msg)
 {
-    if (warningLevel>0) {
-        fprintf(stderr,"%s: line %d of %s\n",msg,yylineno,
-                                        (scanFile?scanFile:"(unknown)"));
-        if (warningLevel>3)
-            fprintf(stderr,"last scanned symbol is: %s\n",scanBuf);
+    struct scanner_extra *extra = yyget_extra(scanner);
+
+    if (warningLevel > 0) {
+        fprintf(stderr, "%s: line %d of %s\n", msg, loc->first_line,
+                extra->scanFile ? extra->scanFile : "(unknown)");
+        if (warningLevel > 3)
+            fprintf(stderr, "last scanned symbol is: %s\n", extra->scanBuf);
     }
     return;
 }
 
-void setScanState(const char *file, int lineno)
-{
-  yylineno = 1;
-  free(scanFile);
-  scanFile = strdup(file);
-}
-
 int
-XKBParseString(const char *string, XkbFile ** pRtrn)
+XKBParseString(const char *string, const char *fileName, XkbFile **pRtrn)
 {
     YY_BUFFER_STATE state;
+    struct parser_param param;
+    struct scanner_extra extra;
+    int ret;
 
     *pRtrn = NULL;
     if (string == NULL)
-       return 1;
+        return 1;
 
-    state = yy_scan_string(string);
-    rtrnValue = NULL;
-    if (yyparse() != 0)
-       return 0;
+    memset(&extra, 0, sizeof(extra));
+    ret = yylex_init_extra(&extra, &param.scanner);
+    if (ret != 0)
+        return 0;
+    extra.scanFile = strdup(fileName);
+
+    state = yy_scan_string(string, param.scanner);
+    ret = yyparse(&param);
+    yy_delete_buffer(state, param.scanner);
+    yylex_destroy(param.scanner);
+    free(extra.scanFile);
+    if (ret)
+        return 0;
 
-    yy_delete_buffer(state);
-    yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
-    *pRtrn = rtrnValue;
-    CheckDefaultMap(rtrnValue);
-    rtrnValue = NULL;
+    CheckDefaultMap(param.rtrn, fileName);
+    *pRtrn = param.rtrn;
 
     return 1;
 }
 
 int
-XKBParseFile(FILE * file, XkbFile ** pRtrn)
+XKBParseFile(FILE * file, const char *fileName, XkbFile ** pRtrn)
 {
+    int ret;
+    struct parser_param param;
+    struct scanner_extra extra;
+
     *pRtrn = NULL;
     if (!file)
         return 1;
 
-    yyin = file;
-    rtrnValue = NULL;
-    if (yyparse() != 0)
+    memset(&extra, 0, sizeof(extra));
+    if (yylex_init_extra(&extra, &param.scanner) != 0)
+        return 0;
+    extra.scanFile = strdup(fileName);
+
+    yyset_in(file, param.scanner);
+    ret = yyparse(&param);
+    yylex_destroy(param.scanner);
+    free(extra.scanFile);
+    if (ret)
         return 0;
 
-    yylex_destroy();
-    *pRtrn = rtrnValue;
-    CheckDefaultMap(rtrnValue);
-    rtrnValue = NULL;
+    CheckDefaultMap(param.rtrn, fileName);
+    *pRtrn = param.rtrn;
     return 1;
 }