mirror of
https://github.com/ascii-boxes/boxes.git
synced 2024-12-04 14:03:53 +01:00
Refactor lexer and parser for maintainability
- Speedmode is now purely a parser thing - Lexer start condition SPEEDMODE is no longer needed - Added lexer start condition BOX to distinguish box def content - DELIMs are now purely a lexer thing - No shared state between lexer and parser for DELIMs anymore - Fix bug where speedmode could terminate in a SAMPLE block - All lexer start conditions now exclusive - Improved debug output - Renamed parser token YDELWORD to YDELIMSPEC
This commit is contained in:
parent
00153f8068
commit
2d3a842728
216
src/lexer.l
216
src/lexer.l
@ -29,16 +29,20 @@
|
||||
typedef struct {
|
||||
int yyerrcnt;
|
||||
|
||||
/** pointer to the currently active string delimiter character in bison_args */
|
||||
char *sdel_ptr;
|
||||
/** the currently active string delimiter character */
|
||||
char sdel;
|
||||
|
||||
/** pointer to the currently active string escape character in bison_args */
|
||||
char *sesc_ptr;
|
||||
/** the currently active string escape character */
|
||||
char sesc;
|
||||
} pass_to_flex;
|
||||
|
||||
|
||||
|
||||
void begin_speedmode(void *yyscanner);
|
||||
/*
|
||||
* Valid characters to be used as string delimiters. Note that the
|
||||
* following list must correspond to the SDELIM definition below.
|
||||
*/
|
||||
#define LEX_SDELIM "\"~'`!@%&*=:;<>?/|.\\"
|
||||
#define LEX_SDELIM_RECOMMENDED "\"~'!|"
|
||||
|
||||
|
||||
/**
|
||||
@ -73,6 +77,8 @@ static void report_state_char(char *symbol, char c, char *expected_state_str);
|
||||
|
||||
static void report_state(char *symbol, char *text, char *expected_state_str);
|
||||
|
||||
static int change_string_delimiters(pass_to_flex *extra, char *delim_expr);
|
||||
|
||||
%}
|
||||
|
||||
|
||||
@ -91,17 +97,16 @@ static void report_state(char *symbol, char *text, char *expected_state_str);
|
||||
%option yylineno
|
||||
|
||||
|
||||
%x DELWORD
|
||||
%x PARENT
|
||||
%x BOX
|
||||
%x SAMPLE
|
||||
%x SPEEDMODE
|
||||
%s ELASTIC
|
||||
%s SHAPES
|
||||
%x SHAPES
|
||||
%x ELASTIC
|
||||
%x DELIMSPEC
|
||||
%x PARENT
|
||||
|
||||
|
||||
PWORD [a-zA-ZäöüÄÖÜ][a-zA-Z0-9\-_üäöÜÄÖß]*
|
||||
PWHITE [\n \r\t]
|
||||
PBOX Box
|
||||
PWHITE [ \t\r\n]
|
||||
SDELIM [\"~\'`!@\%\&\*=:;<>\?/|\.\\]
|
||||
PPARENT parent
|
||||
PFILENAME [^\r\n]+
|
||||
@ -109,38 +114,39 @@ PFILENAME [^\r\n]+
|
||||
|
||||
%%
|
||||
|
||||
|
||||
<INITIAL,DELWORD,ELASTIC,SHAPES>[ \r\t] /* ignore whitespace */
|
||||
|
||||
<INITIAL,DELWORD,ELASTIC,SHAPES>\n {}
|
||||
|
||||
|
||||
<DELWORD>[^ \t\r\n]+ {
|
||||
/*
|
||||
* String delimiter spec - like WORD, but allow any character
|
||||
* Precedence of rules:
|
||||
* - The rule that matches the most text wins.
|
||||
* - If two rules match the same amount of text, the one defined first (further up) wins.
|
||||
*/
|
||||
|
||||
|
||||
<INITIAL,BOX,DELIMSPEC,ELASTIC,SHAPES>{PWHITE} /* ignore whitespace */
|
||||
|
||||
<DELIMSPEC>[^ \t\r\n]+ {
|
||||
/*
|
||||
* String delimiter spec - like WORD, but allow any character
|
||||
*/
|
||||
yylval->s = (char *) strdup (yytext);
|
||||
if (yylval->s == NULL) {
|
||||
perror (PROJECT);
|
||||
exit (EXIT_FAILURE);
|
||||
BEGIN(BOX);
|
||||
report_state("YDELIMS", yytext, "INITIAL");
|
||||
if (change_string_delimiters(yyextra, yylval->s) != 0) {
|
||||
return YUNREC;
|
||||
}
|
||||
BEGIN(INITIAL);
|
||||
report_state("YDELWOR", yytext, "INITIAL");
|
||||
return YDELWORD;
|
||||
return YDELIMSPEC;
|
||||
}
|
||||
|
||||
|
||||
{SDELIM}.*$ {
|
||||
<BOX,SHAPES>{SDELIM}.*$ {
|
||||
/*
|
||||
* Strings -- first match everything starting from a potential
|
||||
* string delimiter until the end of the line. We will give back what
|
||||
* we don't need and also detect unterminated strings.
|
||||
* Strings -- first match everything starting from a potential string delimiter until the end of the line. We
|
||||
* will give back what we don't need and also detect unterminated strings. Strings always end on the same line.
|
||||
*/
|
||||
char *p;
|
||||
int rest_len = yyleng - 1; /* length of string pointed to by p */
|
||||
int qcnt = 0; /* esc char count in current string */
|
||||
|
||||
if (yytext[0] != *(yyextra->sdel_ptr)) {
|
||||
if (yytext[0] != yyextra->sdel) {
|
||||
REJECT; /* that was not our delimiter */
|
||||
}
|
||||
|
||||
@ -152,14 +158,14 @@ PFILENAME [^\r\n]+
|
||||
p = yylval->s;
|
||||
|
||||
while (*p) {
|
||||
if (*p == *(yyextra->sesc_ptr)) {
|
||||
if (*p == yyextra->sesc) {
|
||||
memmove (p, p+1, rest_len); /* incl. '\0' */
|
||||
++qcnt;
|
||||
--rest_len;
|
||||
if (*p == '\0')
|
||||
break;
|
||||
}
|
||||
else if (*p == *(yyextra->sdel_ptr)) {
|
||||
else if (*p == yyextra->sdel) {
|
||||
*p = '\0';
|
||||
yyless ((p-yylval->s)+2+qcnt); /* string plus quotes */
|
||||
#ifdef LEXER_DEBUG
|
||||
@ -177,7 +183,7 @@ PFILENAME [^\r\n]+
|
||||
}
|
||||
|
||||
|
||||
{PPARENT} {
|
||||
<INITIAL>{PPARENT} {
|
||||
BEGIN(PARENT);
|
||||
report_state("YPARENT", yytext, "PARENT");
|
||||
return YPARENT;
|
||||
@ -204,19 +210,18 @@ PFILENAME [^\r\n]+
|
||||
report_state(" NL", "", "INITIAL");
|
||||
}
|
||||
|
||||
Sample {
|
||||
|
||||
<BOX>Sample {
|
||||
BEGIN(SAMPLE);
|
||||
report_state("YSAMPLE", yytext, "SAMPLE");
|
||||
return YSAMPLE;
|
||||
}
|
||||
|
||||
|
||||
<SAMPLE>\n {
|
||||
if (yyleng > 1)
|
||||
yymore();
|
||||
}
|
||||
|
||||
|
||||
<SAMPLE>^[ \t]*ends[ \t\r]*$ {
|
||||
char *p = yytext + yyleng -1;
|
||||
size_t len; /* length of sample */
|
||||
@ -239,8 +244,6 @@ Sample {
|
||||
btrim (yylval->s, &len);
|
||||
if (len > 0) {
|
||||
strcat (yylval->s, "\n"); /* memory was allocated with strdup */
|
||||
BEGIN(INITIAL);
|
||||
report_state(" STRING", yylval->s, "INITIAL");
|
||||
return STRING;
|
||||
}
|
||||
else {
|
||||
@ -252,53 +255,56 @@ Sample {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
<SAMPLE>. yymore();
|
||||
|
||||
|
||||
ends[ \t\r]*$ {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "YENDSAM: %s\n", yytext);
|
||||
#endif
|
||||
<SAMPLE>ends[ \t\r]*$ {
|
||||
/* reached because the other rule pushes it back so a proper end token can be returned */
|
||||
BEGIN(BOX);
|
||||
report_state("YENDSAM", yytext, "BOX");
|
||||
return YENDSAMPLE;
|
||||
}
|
||||
|
||||
|
||||
Tags {
|
||||
<BOX>Tags {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, " YTAGS: %s\n", yytext);
|
||||
#endif
|
||||
return YTAGS;
|
||||
}
|
||||
|
||||
Elastic {
|
||||
<BOX>Elastic {
|
||||
BEGIN(ELASTIC);
|
||||
report_state("YELASTC", yytext, "ELASTIC");
|
||||
return YELASTIC;
|
||||
}
|
||||
|
||||
Shapes {
|
||||
<BOX>Shapes {
|
||||
BEGIN(SHAPES);
|
||||
report_state("YSHAPES", yytext, "SHAPES");
|
||||
return YSHAPES;
|
||||
}
|
||||
|
||||
{PBOX} {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, " YBOX: %s\n", yytext);
|
||||
#endif
|
||||
<INITIAL>Box {
|
||||
BEGIN(BOX);
|
||||
report_state(" YBOX", yytext, "BOX");
|
||||
yyextra->yyerrcnt = 0;
|
||||
change_string_delimiters(yyextra, "\\\"");
|
||||
return YBOX;
|
||||
}
|
||||
|
||||
Replace { return YREPLACE; }
|
||||
Reverse { return YREVERSE; }
|
||||
Padding { return YPADDING; }
|
||||
End { return YEND; }
|
||||
To { return YTO; }
|
||||
With { return YWITH; }
|
||||
Global { yylval->c = 'g'; return YRXPFLAG; }
|
||||
Once { yylval->c = 'o'; return YRXPFLAG; }
|
||||
<BOX>Replace { return YREPLACE; }
|
||||
<BOX>Reverse { return YREVERSE; }
|
||||
<BOX>Padding { return YPADDING; }
|
||||
<BOX>To { return YTO; }
|
||||
<BOX>With { return YWITH; }
|
||||
<BOX>Global { yylval->c = 'g'; return YRXPFLAG; }
|
||||
<BOX>Once { yylval->c = 'o'; return YRXPFLAG; }
|
||||
<BOX>End {
|
||||
BEGIN(INITIAL);
|
||||
report_state(" YEND", yytext, "INITIAL");
|
||||
change_string_delimiters(yyextra, "\\\"");
|
||||
return YEND;
|
||||
}
|
||||
|
||||
|
||||
<SHAPES,ELASTIC>nw { yylval->shape = NW; return SHAPE; }
|
||||
@ -319,21 +325,21 @@ Once { yylval->c = 'o'; return YRXPFLAG; }
|
||||
<SHAPES,ELASTIC>wnw { yylval->shape = WNW; return SHAPE; }
|
||||
|
||||
<ELASTIC>\) {
|
||||
BEGIN(INITIAL);
|
||||
report_state_char("SYMBOL", yytext[0], "INITIAL");
|
||||
BEGIN(BOX);
|
||||
report_state_char("SYMBOL", yytext[0], "BOX");
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
<SHAPES>\} {
|
||||
BEGIN(INITIAL);
|
||||
report_state_char("SYMBOL", yytext[0], "INITIAL");
|
||||
BEGIN(BOX);
|
||||
report_state_char("SYMBOL", yytext[0], "BOX");
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
|
||||
author|designer|created|revision|revdate|indent {
|
||||
<BOX>author|designer|created|revision|revdate|indent {
|
||||
/*
|
||||
* general key words
|
||||
* general key words
|
||||
*/
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "KEYWORD: %s\n", yytext);
|
||||
@ -347,17 +353,20 @@ author|designer|created|revision|revdate|indent {
|
||||
}
|
||||
|
||||
|
||||
Delimiter|Delim {
|
||||
<BOX>Delimiter|Delim {
|
||||
/*
|
||||
* Change string delimiting characters
|
||||
* Change string delimiting characters
|
||||
*/
|
||||
BEGIN(DELWORD);
|
||||
report_state("YCHGDEL", yytext, "DELWORD");
|
||||
BEGIN(DELIMSPEC);
|
||||
report_state("YCHGDEL", yytext, "DELIMSPEC");
|
||||
return YCHGDEL;
|
||||
}
|
||||
|
||||
|
||||
{PWORD} {
|
||||
<INITIAL,BOX>{PWORD} {
|
||||
/*
|
||||
* a free-floating word which is not a string, i.e. it does not have delimiting characters
|
||||
*/
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, " WORD: %s\n", yytext);
|
||||
#endif
|
||||
@ -370,7 +379,7 @@ Delimiter|Delim {
|
||||
}
|
||||
|
||||
|
||||
[\+-]?[0-9]+ {
|
||||
<BOX>[\+-]?[0-9]+ {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "YNUMBER: %s\n", yytext);
|
||||
#endif
|
||||
@ -379,7 +388,7 @@ Delimiter|Delim {
|
||||
}
|
||||
|
||||
|
||||
[,(){}] {
|
||||
<BOX,SHAPES,ELASTIC>[,(){}] {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, " SYMBOL: \'%c\'\n", yytext[0]);
|
||||
#endif
|
||||
@ -387,7 +396,7 @@ Delimiter|Delim {
|
||||
}
|
||||
|
||||
|
||||
#.*$ {
|
||||
<INITIAL,BOX,SHAPES,ELASTIC>#.*$ {
|
||||
/* ignore comments */
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "COMMENT: %s\n", yytext+1);
|
||||
@ -395,25 +404,15 @@ Delimiter|Delim {
|
||||
}
|
||||
|
||||
|
||||
. {
|
||||
if ((yyextra->yyerrcnt)++ < LEX_MAX_WARN)
|
||||
yyerror(NULL, "Unrecognized input char \'%s\'", yytext);
|
||||
<INITIAL,BOX,SHAPES,ELASTIC>. {
|
||||
/* a character that made no sense where it was encountered. Let the parser handle it. */
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, " YUNREC: \'%c\'\n", yytext[0]);
|
||||
#endif
|
||||
return YUNREC;
|
||||
}
|
||||
|
||||
|
||||
<SPEEDMODE>{PBOX}{PWHITE}+{PWORD}|{PPARENT} {
|
||||
/* end speedmode, but then give back the whole match so BOX or PARENT can be started properly */
|
||||
yyless(0);
|
||||
BEGIN(INITIAL);
|
||||
report_state(" STATUS", "", "INITIAL");
|
||||
}
|
||||
|
||||
<SPEEDMODE>\n {}
|
||||
|
||||
<SPEEDMODE>. /* ignore anything else */
|
||||
|
||||
|
||||
%%
|
||||
|
||||
|
||||
@ -433,19 +432,10 @@ void inflate_inbuf(void *yyscanner, const char *configfile)
|
||||
|
||||
|
||||
|
||||
void begin_speedmode(void *yyscanner)
|
||||
{
|
||||
struct yyguts_t *yyg = (struct yyguts_t *) yyscanner;
|
||||
BEGIN(SPEEDMODE);
|
||||
report_state(" STATUS", "begin_speedmode()", "SPEEDMODE");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void report_state_char(char *symbol, char c, char *expected_state_str)
|
||||
{
|
||||
char *s = (char *) malloc(4);
|
||||
sprintf(s, "'%c'", c);
|
||||
sprintf(s, "'%c'", c >= ' ' && c <= 126 ? c : '?');
|
||||
report_state(symbol, s, expected_state_str);
|
||||
BFREE(s);
|
||||
}
|
||||
@ -464,4 +454,30 @@ static void report_state(char *symbol, char *text, char *expected_state_str)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int change_string_delimiters(pass_to_flex *extra, char *delim_expr)
|
||||
{
|
||||
if (strlen(delim_expr) != 2) {
|
||||
yyerror(NULL, "invalid string delimiter specification -- %s", delim_expr);
|
||||
return 1;
|
||||
}
|
||||
if (delim_expr[0] == delim_expr[1]) {
|
||||
yyerror(NULL, "string delimiter and escape char may not be the same");
|
||||
return 1;
|
||||
}
|
||||
if (strchr (LEX_SDELIM, delim_expr[1]) == NULL) {
|
||||
yyerror(NULL, "invalid string delimiter -- %c (try one of %s)", delim_expr[1], LEX_SDELIM_RECOMMENDED);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf(stderr, "YDELIMS: change_string_delimiters('%c', '%c')\n", delim_expr[0], delim_expr[1]);
|
||||
#endif
|
||||
extra->sesc = delim_expr[0];
|
||||
extra->sdel = delim_expr[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*EOF*/ /* vim: set cindent sw=4: */
|
||||
|
@ -39,48 +39,11 @@
|
||||
#include "lex.yy.h"
|
||||
|
||||
|
||||
/*
|
||||
* Valid characters to be used as string delimiters. Note that the
|
||||
* following list must correspond to the DELIM definition in lexer.l.
|
||||
*/
|
||||
#define LEX_SDELIM "\"~'`!@%&*=:;<>?/|.\\"
|
||||
|
||||
static pcre2_code *eol_pattern = NULL;
|
||||
|
||||
|
||||
|
||||
static void chg_strdelims (pass_to_bison *bison_args, const char asesc, const char asdel)
|
||||
{
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, " STATUS: chg_strdelims ('%c', '%c') - This changes lexer behavior!\n", asesc, asdel);
|
||||
#endif
|
||||
bison_args->sesc = asesc;
|
||||
bison_args->sdel = asdel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int action_chg_delim(pass_to_bison *bison_args, char *delim_expr)
|
||||
{
|
||||
if (strlen(delim_expr) != 2) {
|
||||
yyerror(bison_args, "invalid string delimiter specification -- %s", delim_expr);
|
||||
return RC_ERROR;
|
||||
}
|
||||
if (delim_expr[0] == delim_expr[1]) {
|
||||
yyerror(bison_args, "string delimiter and escape char may not be the same");
|
||||
return RC_ERROR;
|
||||
}
|
||||
if (strchr (LEX_SDELIM, delim_expr[1]) == NULL) {
|
||||
yyerror(bison_args, "invalid string delimiter -- %c (try one of %s)",
|
||||
delim_expr[1], LEX_SDELIM);
|
||||
return RC_ERROR;
|
||||
}
|
||||
chg_strdelims(bison_args, delim_expr[0], delim_expr[1]);
|
||||
return RC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int check_sizes(pass_to_bison *bison_args)
|
||||
/*
|
||||
* For the author's convenience, it is required that shapes on one side
|
||||
@ -95,7 +58,7 @@ static int check_sizes(pass_to_bison *bison_args)
|
||||
int i, j, k;
|
||||
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "check_sizes()\n");
|
||||
fprintf (stderr, " Parser: check_sizes()\n");
|
||||
#endif
|
||||
|
||||
for (i=0; i<NUM_SIDES; ++i) {
|
||||
@ -163,7 +126,7 @@ static int corner_check(pass_to_bison *bison_args)
|
||||
int c;
|
||||
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "corner_check()\n");
|
||||
fprintf (stderr, " Parser: corner_check()\n");
|
||||
#endif
|
||||
|
||||
for (c=0; c<NUM_CORNERS; ++c) {
|
||||
@ -183,7 +146,7 @@ static shape_t non_existent_elastics(pass_to_bison *bison_args)
|
||||
shape_t i;
|
||||
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "non_existent_elastics()\n");
|
||||
fprintf (stderr, " Parser: non_existent_elastics()\n");
|
||||
#endif
|
||||
|
||||
for (i=0; i<NUM_SHAPES; ++i) {
|
||||
@ -202,7 +165,7 @@ static int insufficient_elasticity(pass_to_bison *bison_args)
|
||||
int i, j, ef;
|
||||
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "insufficient_elasticity()\n");
|
||||
fprintf (stderr, " Parser: insufficient_elasticity()\n");
|
||||
#endif
|
||||
|
||||
for (i=0; i<NUM_SIDES; ++i) {
|
||||
@ -226,7 +189,7 @@ static int adjoining_elastics(pass_to_bison *bison_args)
|
||||
int i, j, ef;
|
||||
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "adjoining_elastics()\n");
|
||||
fprintf (stderr, " Parser: adjoining_elastics()\n");
|
||||
#endif
|
||||
|
||||
for (i=0; i<NUM_SIDES; ++i) {
|
||||
@ -304,7 +267,6 @@ void recover(pass_to_bison *bison_args)
|
||||
bison_args->num_mandatory = 0;
|
||||
bison_args->time_for_se_check = 0;
|
||||
bison_args->num_shapespec = 0;
|
||||
chg_strdelims(bison_args, '\\', '\"');
|
||||
|
||||
/*
|
||||
* Clear current design
|
||||
@ -358,7 +320,7 @@ static int full_parse_required()
|
||||
result = opt.r || opt.l || (opt.query != NULL && !query_is_undoc());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "full_parse_required() -> %s\n", result ? "true" : "false");
|
||||
fprintf(stderr, " Parser: full_parse_required() -> %s\n", result ? "true" : "false");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
@ -642,9 +604,9 @@ int action_finalize_shapes(pass_to_bison *bison_args)
|
||||
}
|
||||
}
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "Minimum box dimensions: width %d height %d\n",
|
||||
fprintf (stderr, " Parser: Minimum box dimensions: width %d height %d\n",
|
||||
(int) curdes.minwidth, (int) curdes.minheight);
|
||||
fprintf (stderr, "Maximum shape height: %d\n",
|
||||
fprintf (stderr, " Parser: Maximum shape height: %d\n",
|
||||
(int) curdes.maxshapeheight);
|
||||
#endif
|
||||
return RC_SUCCESS;
|
||||
@ -662,7 +624,6 @@ int action_finalize_shapes(pass_to_bison *bison_args)
|
||||
*/
|
||||
int action_start_parsing_design(pass_to_bison *bison_args, char *design_name)
|
||||
{
|
||||
chg_strdelims(bison_args, '\\', '\"');
|
||||
bison_args->speeding = 0;
|
||||
bison_args->skipping = 0;
|
||||
|
||||
@ -674,9 +635,10 @@ int action_start_parsing_design(pass_to_bison *bison_args, char *design_name)
|
||||
|
||||
if (!design_needed(bison_args)) {
|
||||
bison_args->speeding = 1;
|
||||
begin_speedmode(bison_args->lexer_state);
|
||||
init_design(bison_args, &(curdes));
|
||||
return RC_ERROR;
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, " Parser: Skipping to next design (lexer doesn't know!)\n");
|
||||
#endif
|
||||
return RC_ERROR; /* trigger the parser's `error` rule, which will skip to the next design */
|
||||
}
|
||||
return RC_SUCCESS;
|
||||
}
|
||||
@ -693,7 +655,7 @@ int action_start_parsing_design(pass_to_bison *bison_args, char *design_name)
|
||||
int action_parent_config(pass_to_bison *bison_args, char *filepath)
|
||||
{
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "parent config file specified: [%s]\n", filepath);
|
||||
fprintf (stderr, " Parser: parent config file specified: [%s]\n", filepath);
|
||||
#endif
|
||||
if (filepath == NULL || filepath[0] == '\0') {
|
||||
bison_args->skipping = 1;
|
||||
@ -720,13 +682,13 @@ int action_parent_config(pass_to_bison *bison_args, char *filepath)
|
||||
}
|
||||
}
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "parent config file path resolved: [%s]\n", filepath);
|
||||
fprintf (stderr, " Parser: parent config file path resolved: [%s]\n", filepath);
|
||||
#endif
|
||||
|
||||
int is_new = !array_contains(bison_args->parent_configs, bison_args->num_parent_configs, filepath);
|
||||
if (!is_new) {
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "duplicate parent / cycle: [%s]\n", filepath);
|
||||
fprintf (stderr, " Parser: duplicate parent / cycle: [%s]\n", filepath);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
@ -822,7 +784,7 @@ int action_add_design(pass_to_bison *bison_args, char *design_primary_name, char
|
||||
int action_record_keyword(pass_to_bison *bison_args, char *keyword, char *value)
|
||||
{
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "entry rule fulfilled [%s = %s]\n", keyword, value);
|
||||
fprintf (stderr, " Parser: entry rule fulfilled [%s = %s]\n", keyword, value);
|
||||
#endif
|
||||
if (strcasecmp (keyword, "author") == 0) {
|
||||
curdes.author = (char *) strdup (value);
|
||||
@ -946,7 +908,7 @@ int action_add_alias(pass_to_bison *bison_args, char *alias_name)
|
||||
}
|
||||
if (alias_exists_in_child_configs(bison_args, alias_name)) {
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "alias already used by child config, dropping: %s\n", alias_name);
|
||||
fprintf (stderr, " Parser: alias already used by child config, dropping: %s\n", alias_name);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
@ -978,7 +940,7 @@ static char *adjust_eols(char *sample)
|
||||
int action_sample_block(pass_to_bison *bison_args, char *sample)
|
||||
{
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf(stderr, "SAMPLE block rule satisfied\n");
|
||||
fprintf(stderr, " Parser: SAMPLE block rule satisfied\n");
|
||||
#endif
|
||||
|
||||
if (curdes.sample) {
|
||||
|
@ -48,9 +48,6 @@
|
||||
int action_init_parser(pass_to_bison *bison_args);
|
||||
|
||||
|
||||
int action_chg_delim(pass_to_bison *bison_args, char *delim_expr);
|
||||
|
||||
|
||||
/**
|
||||
* Rule action called when a shape list was fully parsed.
|
||||
* @param bison_args the parser state
|
||||
|
28
src/parser.y
28
src/parser.y
@ -47,12 +47,6 @@ typedef struct {
|
||||
/** the path to the config file we are parsing */
|
||||
char *config_file;
|
||||
|
||||
/** the currently active string delimiter character */
|
||||
char sdel;
|
||||
|
||||
/** the currently active string escape character */
|
||||
char sesc;
|
||||
|
||||
int num_mandatory;
|
||||
|
||||
int time_for_se_check;
|
||||
@ -140,7 +134,7 @@ typedef struct {
|
||||
%token <shape> SHAPE
|
||||
%token <num> YNUMBER
|
||||
%token <c> YRXPFLAG
|
||||
%token <s> YDELWORD
|
||||
%token <s> YDELIMSPEC
|
||||
|
||||
%type <sentry> shape_def
|
||||
%type <sentry> shape_lines
|
||||
@ -203,7 +197,16 @@ config_file: config_file design_or_error | design_or_error | config_file parent_
|
||||
|
||||
design_or_error: design | error
|
||||
{
|
||||
if (!(bison_args->speeding) && !(bison_args->skipping)) {
|
||||
/* reset alias list, as those are collected even when speedmode is on */
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, " Parser: Discarding token [skipping=%s, speeding=%s]\n",
|
||||
bison_args->skipping ? "true" : "false", bison_args->speeding ? "true" : "false");
|
||||
#endif
|
||||
if (curdes.aliases[0] != NULL) {
|
||||
BFREE(curdes.aliases);
|
||||
curdes.aliases = (char **) calloc(1, sizeof(char *));
|
||||
}
|
||||
if (!bison_args->speeding && !bison_args->skipping) {
|
||||
recover(bison_args);
|
||||
yyerror(bison_args, "skipping to next design");
|
||||
bison_args->skipping = 1;
|
||||
@ -260,14 +263,14 @@ entry: KEYWORD STRING
|
||||
}
|
||||
else {
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "%s: Discarding entry [%s = %s].\n", PROJECT, "parent", filename);
|
||||
fprintf (stderr, " Parser: Discarding entry [%s = %s].\n", "parent", filename);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
| YCHGDEL YDELWORD
|
||||
| YCHGDEL YDELIMSPEC
|
||||
{
|
||||
invoke_action(action_chg_delim(bison_args, $2));
|
||||
/* string delimiters were changed - this is a lexer thing. ignore here. */
|
||||
}
|
||||
|
||||
| YTAGS '(' tag_list ')' | YTAGS tag_entry
|
||||
@ -275,7 +278,7 @@ entry: KEYWORD STRING
|
||||
| WORD STRING
|
||||
{
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "%s: Discarding entry [%s = %s].\n", PROJECT, $1, $2);
|
||||
fprintf (stderr, " Parser: Discarding entry [%s = %s].\n", $1, $2);
|
||||
#endif
|
||||
}
|
||||
;
|
||||
@ -492,4 +495,5 @@ wlist_entry: WORD YNUMBER
|
||||
|
||||
%%
|
||||
|
||||
|
||||
/*EOF*/ /* vim: set sw=4 cindent: */
|
||||
|
@ -135,8 +135,6 @@ static pass_to_bison new_bison_args(const char *config_file)
|
||||
bison_args.num_designs = 0;
|
||||
bison_args.design_idx = 0;
|
||||
bison_args.config_file = (char *) config_file;
|
||||
bison_args.sdel = '\"'; /* sdel is shared by flex and bison */
|
||||
bison_args.sesc = '\\'; /* sesc is shared by flex and bison */
|
||||
bison_args.num_mandatory = 0;
|
||||
bison_args.time_for_se_check = 0;
|
||||
bison_args.num_shapespec = 0;
|
||||
@ -150,12 +148,12 @@ static pass_to_bison new_bison_args(const char *config_file)
|
||||
|
||||
|
||||
|
||||
static pass_to_flex new_flex_extra_data(pass_to_bison *bison_args)
|
||||
static pass_to_flex new_flex_extra_data()
|
||||
{
|
||||
pass_to_flex flex_extra_data;
|
||||
flex_extra_data.yyerrcnt = 0;
|
||||
flex_extra_data.sdel_ptr = &(bison_args->sdel);
|
||||
flex_extra_data.sesc_ptr = &(bison_args->sesc);
|
||||
flex_extra_data.sdel = '\"';
|
||||
flex_extra_data.sesc = '\\';
|
||||
return flex_extra_data;
|
||||
}
|
||||
|
||||
@ -170,7 +168,7 @@ static pass_to_bison parse_config_file(const char *config_file, design_t *child_
|
||||
pass_to_bison bison_args = new_bison_args(config_file);
|
||||
bison_args.child_configs = child_configs;
|
||||
bison_args.num_child_configs = num_child_configs;
|
||||
pass_to_flex flex_extra_data = new_flex_extra_data(&bison_args);
|
||||
pass_to_flex flex_extra_data = new_flex_extra_data();
|
||||
current_bison_args = &bison_args;
|
||||
|
||||
yylex_init (&(bison_args.lexer_state));
|
||||
|
@ -11,7 +11,7 @@ that speedmode is properly terminated.)
|
||||
:EXPECTED
|
||||
boxes: 131_data/B.cfg: line 32: entries SAMPLE, SHAPES, and ELASTIC are mandatory
|
||||
boxes: 131_data/B.cfg: line 32: skipping to next design
|
||||
boxes: 131_data/A.cfg: line 29: string expected
|
||||
boxes: 131_data/A.cfg: line 29: syntax error
|
||||
boxes: 131_data/A.cfg: line 29: skipping to next design
|
||||
3 Available Styles:
|
||||
-------------------
|
||||
|
@ -1,5 +1,5 @@
|
||||
:DESC
|
||||
Test that the list of aliases is properly reset when lexer is in speedmode.
|
||||
Test that the list of aliases is properly reset when parser is in speedmode.
|
||||
|
||||
:ARGS
|
||||
-f 137_design_alias_no_accumulation.cfg -d alias3b -l
|
||||
|
33
test/168_parent_keyword_in_sample_ok.cfg
Normal file
33
test/168_parent_keyword_in_sample_ok.cfg
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
BOX designA
|
||||
|
||||
sample
|
||||
A mentions the word parent THIS_IS_NOT_A_CONFIG_FILE
|
||||
ends
|
||||
|
||||
shapes {
|
||||
w ("A")
|
||||
}
|
||||
|
||||
elastic (
|
||||
w
|
||||
)
|
||||
|
||||
END designA
|
||||
|
||||
|
||||
BOX designB
|
||||
|
||||
sample
|
||||
B is the one we select
|
||||
ends
|
||||
|
||||
shapes {
|
||||
w ("B")
|
||||
}
|
||||
|
||||
elastic (
|
||||
w
|
||||
)
|
||||
|
||||
END designB
|
27
test/168_parent_keyword_in_sample_ok.txt
Normal file
27
test/168_parent_keyword_in_sample_ok.txt
Normal file
@ -0,0 +1,27 @@
|
||||
:DESC
|
||||
Test that the keyword 'parent' may occur as a regular string in a sample block, without triggering parent config file
|
||||
resolution.
|
||||
|
||||
:ARGS
|
||||
-f 168_parent_keyword_in_sample_ok.cfg -d designB -l
|
||||
:INPUT
|
||||
:OUTPUT-FILTER
|
||||
:EXPECTED
|
||||
Complete Design Information for "designB":
|
||||
------------------------------------------
|
||||
Alias Names: none
|
||||
Author: (unknown author)
|
||||
Original Designer: (unknown artist)
|
||||
Creation Date: (unknown)
|
||||
Current Revision: (unknown)
|
||||
Configuration File: 168_parent_keyword_in_sample_ok.cfg
|
||||
Indentation Mode: box (indent box)
|
||||
Replacement Rules: none
|
||||
Reversion Rules: none
|
||||
Minimum Box Dimensions: 3 x 3 (width x height)
|
||||
Default Padding: none
|
||||
Default Killblank: no
|
||||
Tags: none
|
||||
Elastic Shapes: N, E, S, W
|
||||
Defined Shapes: W: "B"
|
||||
:EOF
|
Loading…
Reference in New Issue
Block a user