Make parser and scanner reentrant

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.]
master
Ran Benita 2012-03-27 22:41:22 +01:00 committed by Daniel Stone
parent 034ffce664
commit bb6ca7682c
7 changed files with 162 additions and 133 deletions

View 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",

View 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;

View File

@ -28,13 +28,19 @@
#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 */

View 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;
}

View File

@ -33,8 +33,6 @@
#include "XKBcommonint.h"
#include "xkbmisc.h"
extern char *scanFile;
#define TypeUnknown 0
#define TypeBoolean 1
#define TypeInt 2

View File

@ -24,6 +24,26 @@
********************************************************/
%{
#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
@ -88,19 +108,7 @@
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

View File

@ -31,25 +31,26 @@
#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);
yy_delete_buffer(state);
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
*pRtrn = rtrnValue;
CheckDefaultMap(rtrnValue);
rtrnValue = NULL;
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;
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;
}