mirror of
https://github.com/ascii-boxes/boxes.git
synced 2025-03-20 01:27:05 +01:00
parent
46aab3faa6
commit
97b62dd09a
@ -94,7 +94,7 @@ tools.o: tools.c tools.h boxes.h shape.h unicode.h config.h | check_dir
|
||||
unicode.o: unicode.c unicode.h boxes.h tools.h config.h | check_dir
|
||||
shape.o: shape.c shape.h boxes.h tools.h config.h | check_dir
|
||||
generate.o: generate.c generate.h boxes.h shape.h tools.h unicode.h config.h | check_dir
|
||||
parsing.o: parsing.c parsing.h boxes.h config.h | check_dir
|
||||
parsing.o: parsing.c parsing.h parser.h lex.yy.h boxes.h tools.h config.h | check_dir
|
||||
remove.o: remove.c remove.h boxes.h shape.h tools.h unicode.h config.h | check_dir
|
||||
regulex.o: regulex.c regulex.h boxes.h tools.h unicode.h config.h | check_dir
|
||||
getopt.o: misc/getopt.c misc/getopt.h | check_dir
|
||||
|
200
src/lexer.l
200
src/lexer.l
@ -25,10 +25,20 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void begin_speedmode();
|
||||
|
||||
typedef struct {
|
||||
int yyerrcnt;
|
||||
|
||||
/** pointer to the currently active string delimiter character in bison_args */
|
||||
char *sdel_ptr;
|
||||
|
||||
/** pointer to the currently active string escape character in bison_args */
|
||||
char *sesc_ptr;
|
||||
} pass_to_flex;
|
||||
|
||||
|
||||
void chg_strdelims (const char asdel, const char asesc);
|
||||
|
||||
void begin_speedmode(void *yyscanner);
|
||||
|
||||
|
||||
/**
|
||||
@ -38,10 +48,10 @@ void chg_strdelims (const char asdel, const char asesc);
|
||||
* dynamically enlarge its input buffer to accomodate larger tokens. Thus, we simply set the buffer size to the
|
||||
* input file size plus 10 bytes margin-of-error.
|
||||
*
|
||||
* @param scanner pointer to the scanner data block
|
||||
* @param yyscanner pointer to the scanner data block
|
||||
* @param configfile the path to the config file we are reading
|
||||
*/
|
||||
void inflate_inbuf(void *scanner, const char *configfile);
|
||||
void inflate_inbuf(void *yyscanner, const char *configfile);
|
||||
|
||||
}
|
||||
|
||||
@ -49,6 +59,7 @@ void inflate_inbuf(void *scanner, const char *configfile);
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "shape.h"
|
||||
#define FILE_LEXER_L
|
||||
#include "boxes.h"
|
||||
@ -60,21 +71,18 @@ void inflate_inbuf(void *scanner, const char *configfile);
|
||||
|
||||
#define LEX_MAX_WARN 3 /* number of lex errors per design */
|
||||
|
||||
static int yyerrcnt = 0;
|
||||
|
||||
/* the currently active string delimiter character */
|
||||
static char sdel = '\"';
|
||||
|
||||
/* the currently active string escape character */
|
||||
static char sesc = '\\';
|
||||
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);
|
||||
|
||||
%}
|
||||
|
||||
|
||||
%option 8bit
|
||||
%option bison-bridge
|
||||
%option case-insensitive
|
||||
%option ecs
|
||||
%option extra-type="pass_to_flex *"
|
||||
%option never-interactive
|
||||
%option nodefault
|
||||
%option noinput
|
||||
@ -85,12 +93,12 @@ static char sesc = '\\';
|
||||
%option yylineno
|
||||
|
||||
|
||||
%x SAMPLE
|
||||
%x SPEEDMODE
|
||||
%x DELWORD
|
||||
%x PARENT
|
||||
%s SHAPES
|
||||
%x SAMPLE
|
||||
%x SPEEDMODE
|
||||
%s ELASTIC
|
||||
%s SHAPES
|
||||
|
||||
|
||||
PWORD [a-zA-ZäöüÄÖÜ][a-zA-Z0-9\-_üäöÜÄÖß]*
|
||||
@ -104,24 +112,22 @@ PFILENAME [^\r\n]+
|
||||
%%
|
||||
|
||||
|
||||
<DELWORD,SHAPES,ELASTIC,INITIAL>[ \r\t] /* ignore whitespace */
|
||||
<INITIAL,DELWORD,ELASTIC,SHAPES>[ \r\t] /* ignore whitespace */
|
||||
|
||||
<DELWORD,SHAPES,ELASTIC,INITIAL>\n {}
|
||||
<INITIAL,DELWORD,ELASTIC,SHAPES>\n {}
|
||||
|
||||
|
||||
<DELWORD>[^ \t\r\n]+ {
|
||||
/*
|
||||
* String delimiter spec - like WORD, but allow any character
|
||||
*/
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYDELWOR: %s -- STATE INITIAL", yytext);
|
||||
#endif
|
||||
yylval->s = (char *) strdup (yytext);
|
||||
if (yylval->s == NULL) {
|
||||
perror (PROJECT);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
BEGIN INITIAL;
|
||||
BEGIN(INITIAL);
|
||||
report_state("YDELWOR", yytext, "INITIAL");
|
||||
return YDELWORD;
|
||||
}
|
||||
|
||||
@ -136,7 +142,7 @@ PFILENAME [^\r\n]+
|
||||
int rest_len = yyleng - 1; /* length of string pointed to by p */
|
||||
int qcnt = 0; /* esc char count in current string */
|
||||
|
||||
if (yytext[0] != sdel) {
|
||||
if (yytext[0] != *(yyextra->sdel_ptr)) {
|
||||
REJECT; /* that was not our delimiter */
|
||||
}
|
||||
|
||||
@ -148,35 +154,34 @@ PFILENAME [^\r\n]+
|
||||
p = yylval->s;
|
||||
|
||||
while (*p) {
|
||||
if (*p == sesc) {
|
||||
if (*p == *(yyextra->sesc_ptr)) {
|
||||
memmove (p, p+1, rest_len); /* incl. '\0' */
|
||||
++qcnt;
|
||||
--rest_len;
|
||||
if (*p == '\0')
|
||||
break;
|
||||
}
|
||||
else if (*p == sdel) {
|
||||
else if (*p == *(yyextra->sdel_ptr)) {
|
||||
*p = '\0';
|
||||
yyless ((p-yylval->s)+2+qcnt); /* string plus quotes */
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STRING: \"%s\"", yylval->s);
|
||||
fprintf (stderr, " STRING: \"%s\"\n", yylval->s);
|
||||
#endif
|
||||
return STRING;
|
||||
}
|
||||
--rest_len;
|
||||
++p;
|
||||
}
|
||||
if (yyerrcnt++ < 5)
|
||||
if ((yyextra->yyerrcnt)++ < 5) {
|
||||
yyerror(NULL, "Unterminated String -- %s", yytext);
|
||||
}
|
||||
return YUNREC;
|
||||
}
|
||||
|
||||
|
||||
{PPARENT} {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYPARENT: %s", yytext);
|
||||
#endif
|
||||
BEGIN PARENT;
|
||||
BEGIN(PARENT);
|
||||
report_state("YPARENT", yytext, "PARENT");
|
||||
return YPARENT;
|
||||
}
|
||||
|
||||
@ -190,23 +195,20 @@ PFILENAME [^\r\n]+
|
||||
while ((*p == ' ' || *p == '\t') && p >= yylval->s) {
|
||||
*p-- = '\0';
|
||||
}
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STRING: \"%s\"", yylval->s);
|
||||
#endif
|
||||
BEGIN INITIAL;
|
||||
return STRING;
|
||||
BEGIN(INITIAL);
|
||||
report_state("FILENAM", yylval->s, "INITIAL");
|
||||
return FILENAME;
|
||||
}
|
||||
|
||||
<PARENT>\n {
|
||||
BEGIN INITIAL;
|
||||
<PARENT>\r?\n {
|
||||
/* This is triggered only when no parent filename was specified. */
|
||||
BEGIN(INITIAL);
|
||||
report_state(" NL", "", "INITIAL");
|
||||
}
|
||||
|
||||
|
||||
Sample {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYSAMPLE: %s -- STATE SAMPLE", yytext);
|
||||
#endif
|
||||
BEGIN SAMPLE;
|
||||
BEGIN(SAMPLE);
|
||||
report_state("YSAMPLE", yytext, "SAMPLE");
|
||||
return YSAMPLE;
|
||||
}
|
||||
|
||||
@ -235,19 +237,18 @@ Sample {
|
||||
len = p - yytext; /* yyless(n): push back all but the first n */
|
||||
yyless (len); /* allow him to return YENDSAMPLE */
|
||||
|
||||
yylval->s[len] = '\n'; /* replace 'e' with newline */
|
||||
yylval->s[len] = '\n'; /* replace 'e' with newline */
|
||||
btrim (yylval->s, &len);
|
||||
if (len > 0) {
|
||||
strcat (yylval->s, "\n"); /* memory was allocated with strdup */
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STRING: \"%s\" -- STATE INITIAL", yylval->s);
|
||||
#endif
|
||||
BEGIN INITIAL;
|
||||
strcat (yylval->s, "\n"); /* memory was allocated with strdup */
|
||||
BEGIN(INITIAL);
|
||||
report_state(" STRING", yylval->s, "INITIAL");
|
||||
return STRING;
|
||||
}
|
||||
else {
|
||||
if (yyerrcnt++ < 5)
|
||||
if ((yyextra->yyerrcnt)++ < 5) {
|
||||
yyerror(NULL, "SAMPLE block must not be empty");
|
||||
}
|
||||
BFREE (yylval->s);
|
||||
return YUNREC;
|
||||
}
|
||||
@ -259,7 +260,7 @@ Sample {
|
||||
|
||||
ends[ \t\r]*$ {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYENDSAM: %s", yytext);
|
||||
fprintf (stderr, "YENDSAM: %s\n", yytext);
|
||||
#endif
|
||||
return YENDSAMPLE;
|
||||
}
|
||||
@ -267,26 +268,22 @@ ends[ \t\r]*$ {
|
||||
|
||||
|
||||
Elastic {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYELASTC: %s -- STATE ELASTIC", yytext);
|
||||
#endif
|
||||
BEGIN ELASTIC;
|
||||
BEGIN(ELASTIC);
|
||||
report_state("YELASTC", yytext, "ELASTIC");
|
||||
return YELASTIC;
|
||||
}
|
||||
|
||||
Shapes {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYSHAPES: %s -- STATE SHAPES", yytext);
|
||||
#endif
|
||||
BEGIN SHAPES;
|
||||
BEGIN(SHAPES);
|
||||
report_state("YSHAPES", yytext, "SHAPES");
|
||||
return YSHAPES;
|
||||
}
|
||||
|
||||
{PBOX} {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n YBOX: %s", yytext);
|
||||
fprintf (stderr, " YBOX: %s\n", yytext);
|
||||
#endif
|
||||
yyerrcnt = 0;
|
||||
yyextra->yyerrcnt = 0;
|
||||
return YBOX;
|
||||
}
|
||||
|
||||
@ -318,18 +315,14 @@ Once { yylval->c = 'o'; return YRXPFLAG; }
|
||||
<SHAPES,ELASTIC>wnw { yylval->shape = WNW; return SHAPE; }
|
||||
|
||||
<ELASTIC>\) {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n SYMBOL: \'%c\' -- STATE INITIAL", yytext[0]);
|
||||
#endif
|
||||
BEGIN INITIAL;
|
||||
BEGIN(INITIAL);
|
||||
report_state_char("SYMBOL", yytext[0], "INITIAL");
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
<SHAPES>\} {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n SYMBOL: \'%c\' -- STATE INITIAL", yytext[0]);
|
||||
#endif
|
||||
BEGIN INITIAL;
|
||||
BEGIN(INITIAL);
|
||||
report_state_char("SYMBOL", yytext[0], "INITIAL");
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
@ -339,7 +332,7 @@ author|designer|tags|created|revision|revdate|indent {
|
||||
* general key words
|
||||
*/
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nKEYWORD: %s", yytext);
|
||||
fprintf (stderr, "KEYWORD: %s\n", yytext);
|
||||
#endif
|
||||
yylval->s = (char *) strdup (yytext);
|
||||
if (yylval->s == NULL) {
|
||||
@ -354,17 +347,15 @@ Delimiter|Delim {
|
||||
/*
|
||||
* Change string delimiting characters
|
||||
*/
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYCHGDEL: %s -- STATE DELWORD", yytext);
|
||||
#endif
|
||||
BEGIN DELWORD;
|
||||
BEGIN(DELWORD);
|
||||
report_state("YCHGDEL", yytext, "DELWORD");
|
||||
return YCHGDEL;
|
||||
}
|
||||
|
||||
|
||||
{PWORD} {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n WORD: %s", yytext);
|
||||
fprintf (stderr, " WORD: %s\n", yytext);
|
||||
#endif
|
||||
yylval->s = (char *) strdup (yytext);
|
||||
if (yylval->s == NULL) {
|
||||
@ -377,7 +368,7 @@ Delimiter|Delim {
|
||||
|
||||
[\+-]?[0-9]+ {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYNUMBER: %s", yytext);
|
||||
fprintf (stderr, "YNUMBER: %s\n", yytext);
|
||||
#endif
|
||||
yylval->num = atoi (yytext);
|
||||
return YNUMBER;
|
||||
@ -386,7 +377,7 @@ Delimiter|Delim {
|
||||
|
||||
[,(){}] {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n SYMBOL: \'%c\'", yytext[0]);
|
||||
fprintf (stderr, " SYMBOL: \'%c\'\n", yytext[0]);
|
||||
#endif
|
||||
return yytext[0];
|
||||
}
|
||||
@ -395,25 +386,23 @@ Delimiter|Delim {
|
||||
#.*$ {
|
||||
/* ignore comments */
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nCOMMENT: %s", yytext+1);
|
||||
fprintf (stderr, "COMMENT: %s\n", yytext+1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
. {
|
||||
if (yyerrcnt++ < LEX_MAX_WARN)
|
||||
if ((yyextra->yyerrcnt)++ < LEX_MAX_WARN)
|
||||
yyerror(NULL, "Unrecognized input char \'%s\'", yytext);
|
||||
return YUNREC;
|
||||
}
|
||||
|
||||
|
||||
<SPEEDMODE>{PBOX}{PWHITE}+{PWORD} {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STATUS: %s -- STATE INITIAL", yytext);
|
||||
#endif
|
||||
yyless (0);
|
||||
speeding = 0;
|
||||
BEGIN INITIAL;
|
||||
<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 {}
|
||||
@ -424,11 +413,7 @@ Delimiter|Delim {
|
||||
%%
|
||||
|
||||
|
||||
/* TODO These functions should go away. The cast to (struct yyguts_t *) is a hack.
|
||||
* And they use global variables which is not reentrant at all. Use extra data instead.
|
||||
* Maybe inflate_inbuf() can be moved to parsing.c? */
|
||||
|
||||
void inflate_inbuf(void *scanner, const char *configfile)
|
||||
void inflate_inbuf(void *yyscanner, const char *configfile)
|
||||
{
|
||||
struct stat sinf;
|
||||
|
||||
@ -436,31 +421,42 @@ void inflate_inbuf(void *scanner, const char *configfile)
|
||||
perror (PROJECT);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
struct yyguts_t *yyg = (struct yyguts_t *) scanner;
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER, scanner);
|
||||
yy_switch_to_buffer (yy_create_buffer(yyin, sinf.st_size+10, scanner), scanner);
|
||||
struct yyguts_t *yyg = (struct yyguts_t *) yyscanner;
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner);
|
||||
yy_switch_to_buffer (yy_create_buffer(yyin, sinf.st_size+10, yyscanner), yyscanner);
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void begin_speedmode(void *scanner)
|
||||
void begin_speedmode(void *yyscanner)
|
||||
{
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STATUS: begin_speedmode() -- STATE SPEEDMODE");
|
||||
#endif
|
||||
struct yyguts_t *yyg = (struct yyguts_t *) scanner;
|
||||
BEGIN SPEEDMODE;
|
||||
struct yyguts_t *yyg = (struct yyguts_t *) yyscanner;
|
||||
BEGIN(SPEEDMODE);
|
||||
report_state(" STATUS", "begin_speedmode()", "SPEEDMODE");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void chg_strdelims (const char asesc, const char asdel)
|
||||
static void report_state_char(char *symbol, char c, char *expected_state_str)
|
||||
{
|
||||
char *s = (char *) malloc(4);
|
||||
sprintf(s, "'%c'", c);
|
||||
report_state(symbol, s, expected_state_str);
|
||||
BFREE(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void report_state(char *symbol, char *text, char *expected_state_str)
|
||||
{
|
||||
int lexerDebug = 0;
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STATUS: chg_strdelims ('%c', '%c')", asesc, asdel);
|
||||
lexerDebug = 1;
|
||||
#endif
|
||||
sesc = asesc;
|
||||
sdel = asdel;
|
||||
if (lexerDebug) {
|
||||
fprintf(stderr, "%7s: %s -- STATE %s\n", symbol, text, expected_state_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
139
src/parser.y
139
src/parser.y
@ -25,7 +25,6 @@
|
||||
|
||||
#include "boxes.h"
|
||||
|
||||
extern int speeding;
|
||||
|
||||
/** all the arguments which we pass to the bison parser */
|
||||
typedef struct {
|
||||
@ -41,6 +40,31 @@ 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;
|
||||
|
||||
/** number of user-specified shapes */
|
||||
int num_shapespec;
|
||||
|
||||
/** used to limit "skipping" msgs */
|
||||
int skipping;
|
||||
|
||||
/** true if we're skipping designs, but no error */
|
||||
int speeding;
|
||||
|
||||
/** names of config files specified via "parent" */
|
||||
char **parent_configs;
|
||||
|
||||
/** number of parent config files (size of parent_configs array) */
|
||||
size_t num_parent_configs;
|
||||
|
||||
/** the flex scanner, which is explicitly passed to reentrant bison */
|
||||
void *lexer_state;
|
||||
} pass_to_bison;
|
||||
@ -62,13 +86,13 @@ typedef struct {
|
||||
#include "parser.h"
|
||||
#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 "\"~'`!@%&*=:;<>?/|.\\"
|
||||
|
||||
|
||||
/** required for bison-flex bridge */
|
||||
#define scanner bison_args->lexer_state
|
||||
|
||||
@ -76,14 +100,6 @@ typedef struct {
|
||||
#define curdes (bison_args->designs[bison_args->design_idx])
|
||||
|
||||
|
||||
static int num_mandatory = 0;
|
||||
static int time_for_se_check = 0;
|
||||
static int num_shapespec = 0; /* number of user-specified shapes */
|
||||
|
||||
int speeding = 0; /* true if we're skipping designs, but no error */
|
||||
static int skipping = 0; /* used to limit "skipping" msgs */
|
||||
|
||||
|
||||
|
||||
static int check_sizes(pass_to_bison *bison_args)
|
||||
/*
|
||||
@ -293,6 +309,17 @@ static int perform_se_check(pass_to_bison *bison_args)
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void recover(pass_to_bison *bison_args)
|
||||
/*
|
||||
* Reset parser to neutral state, so a new design can be parsed.
|
||||
@ -300,10 +327,10 @@ static void recover(pass_to_bison *bison_args)
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
{
|
||||
num_mandatory = 0;
|
||||
time_for_se_check = 0;
|
||||
num_shapespec = 0;
|
||||
chg_strdelims ('\\', '\"');
|
||||
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 +385,6 @@ static int design_needed (const char *name, const int design_idx)
|
||||
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|_*/
|
||||
|
||||
%define api.pure true
|
||||
%pure-parser
|
||||
%lex-param {void *scanner}
|
||||
%parse-param {pass_to_bison *bison_args}
|
||||
|
||||
@ -375,6 +401,7 @@ static int design_needed (const char *name, const int design_idx)
|
||||
%token <s> KEYWORD
|
||||
%token <s> WORD
|
||||
%token <s> STRING
|
||||
%token <s> FILENAME
|
||||
%token <shape> SHAPE
|
||||
%token <num> YNUMBER
|
||||
%token <c> YRXPFLAG
|
||||
@ -410,6 +437,7 @@ first_rule:
|
||||
YYABORT;
|
||||
}
|
||||
bison_args->num_designs = 1;
|
||||
|
||||
bison_args->designs->indentmode = DEF_INDENTMODE;
|
||||
bison_args->designs->defined_in = bison_args->config_file;
|
||||
}
|
||||
@ -424,14 +452,11 @@ config_file
|
||||
if (bison_args->design_idx == 0) {
|
||||
BFREE (bison_args->designs);
|
||||
bison_args->num_designs = 0;
|
||||
if (opt.design_choice_by_user) {
|
||||
fprintf (stderr, "%s: unknown box design -- %s\n",
|
||||
PROJECT, (char *) opt.design);
|
||||
if (!opt.design_choice_by_user && bison_args->num_parent_configs == 0) {
|
||||
fprintf (stderr, "%s: no valid data in config file -- %s\n", PROJECT, bison_args->config_file);
|
||||
YYABORT;
|
||||
}
|
||||
else {
|
||||
yyerror(bison_args, "no valid designs found");
|
||||
}
|
||||
YYABORT;
|
||||
YYACCEPT;
|
||||
}
|
||||
|
||||
--(bison_args->design_idx);
|
||||
@ -444,21 +469,21 @@ config_file
|
||||
bison_args->designs = tmp;
|
||||
}
|
||||
|
||||
parent_def: YPARENT STRING
|
||||
parent_def: YPARENT FILENAME
|
||||
{
|
||||
char *filepath = $2;
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "parent config file specified: [%s]\n", filepath);
|
||||
#endif
|
||||
if (filepath == NULL || filepath[0] == '\0') {
|
||||
skipping = 1;
|
||||
bison_args->skipping = 1;
|
||||
yyerror(bison_args, "parent reference is empty");
|
||||
YYERROR;
|
||||
}
|
||||
else if (strcasecmp(filepath, ":global:") == 0) { /* special token */
|
||||
filepath = discover_config_file(1);
|
||||
if (filepath == NULL) {
|
||||
skipping = 1; /* prevent redundant "skipping to next design" message */
|
||||
bison_args->skipping = 1; /* prevent redundant "skipping to next design" message */
|
||||
yyerror(bison_args, "parent reference to global config which cannot be found");
|
||||
YYERROR;
|
||||
}
|
||||
@ -466,7 +491,7 @@ parent_def: YPARENT STRING
|
||||
else {
|
||||
FILE *f = fopen(filepath, "r");
|
||||
if (f == NULL) {
|
||||
skipping = 1;
|
||||
bison_args->skipping = 1;
|
||||
yyerror(bison_args, "parent config file not found: %s", filepath);
|
||||
YYERROR;
|
||||
}
|
||||
@ -478,16 +503,17 @@ parent_def: YPARENT STRING
|
||||
fprintf (stderr, "parent config file path resolved: [%s]\n", filepath);
|
||||
#endif
|
||||
|
||||
int is_new = !array_contains(parent_configs, num_parent_configs, filepath);
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
parent_configs = realloc(parent_configs, (num_parent_configs + 1) * sizeof(char *));
|
||||
parent_configs[num_parent_configs] = filepath;
|
||||
++num_parent_configs;
|
||||
bison_args->parent_configs = realloc(bison_args->parent_configs,
|
||||
(bison_args->num_parent_configs + 1) * sizeof(char *));
|
||||
bison_args->parent_configs[bison_args->num_parent_configs] = filepath;
|
||||
++(bison_args->num_parent_configs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,20 +522,21 @@ config_file: config_file design_or_error | design_or_error | config_file parent_
|
||||
|
||||
design_or_error: design | error
|
||||
{
|
||||
if (!speeding && !skipping) {
|
||||
if (!(bison_args->speeding) && !(bison_args->skipping)) {
|
||||
recover(bison_args);
|
||||
yyerror(bison_args, "skipping to next design");
|
||||
skipping = 1;
|
||||
bison_args->skipping = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
design: YBOX WORD
|
||||
{
|
||||
chg_strdelims ('\\', '\"');
|
||||
skipping = 0;
|
||||
chg_strdelims(bison_args, '\\', '\"');
|
||||
bison_args->speeding = 0;
|
||||
bison_args->skipping = 0;
|
||||
if (!design_needed ($2, bison_args->design_idx)) {
|
||||
speeding = 1;
|
||||
bison_args->speeding = 1;
|
||||
begin_speedmode(scanner);
|
||||
YYERROR;
|
||||
}
|
||||
@ -529,7 +556,7 @@ layout YEND WORD
|
||||
yyerror(bison_args, "box design name differs at BOX and END");
|
||||
YYERROR;
|
||||
}
|
||||
if (num_mandatory < 3) {
|
||||
if (bison_args->num_mandatory < 3) {
|
||||
yyerror(bison_args, "entries SAMPLE, SHAPES, and ELASTIC are mandatory");
|
||||
YYERROR;
|
||||
}
|
||||
@ -556,9 +583,9 @@ layout YEND WORD
|
||||
perror (PROJECT);
|
||||
YYABORT;
|
||||
}
|
||||
num_mandatory = 0;
|
||||
time_for_se_check = 0;
|
||||
num_shapespec = 0;
|
||||
bison_args->num_mandatory = 0;
|
||||
bison_args->time_for_se_check = 0;
|
||||
bison_args->num_shapespec = 0;
|
||||
|
||||
/*
|
||||
* Check if we need to continue parsing. If not, return.
|
||||
@ -655,6 +682,24 @@ entry: KEYWORD STRING
|
||||
}
|
||||
}
|
||||
|
||||
| YPARENT FILENAME
|
||||
{
|
||||
char *filename = $2;
|
||||
if (filename[0] != filename[strlen(filename) - 1]
|
||||
|| (filename[0] >= 'a' && filename[0] <= 'z')
|
||||
|| (filename[0] >= 'A' && filename[0] <= 'Z')
|
||||
|| (filename[0] >= '0' && filename[0] <= '9'))
|
||||
{
|
||||
yyerror(bison_args, "string expected", filename);
|
||||
YYERROR;
|
||||
}
|
||||
else {
|
||||
#ifdef PARSER_DEBUG
|
||||
fprintf (stderr, "%s: Discarding entry [%s = %s].\n", PROJECT, "parent", filename);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
| YCHGDEL YDELWORD
|
||||
{
|
||||
if (strlen($2) != 2) {
|
||||
@ -670,7 +715,7 @@ entry: KEYWORD STRING
|
||||
($2)[1], LEX_SDELIM);
|
||||
YYERROR;
|
||||
}
|
||||
chg_strdelims ($2[0], $2[1]);
|
||||
chg_strdelims(bison_args, $2[0], $2[1]);
|
||||
}
|
||||
|
||||
| WORD STRING
|
||||
@ -704,7 +749,7 @@ block: YSAMPLE STRING YENDSAMPLE
|
||||
}
|
||||
|
||||
curdes.sample = line;
|
||||
++num_mandatory;
|
||||
++(bison_args->num_mandatory);
|
||||
}
|
||||
|
||||
| YSHAPES '{' slist '}'
|
||||
@ -719,7 +764,7 @@ block: YSAMPLE STRING YENDSAMPLE
|
||||
/*
|
||||
* At least one shape must be specified
|
||||
*/
|
||||
if (num_shapespec < 1) {
|
||||
if (bison_args->num_shapespec < 1) {
|
||||
yyerror(bison_args, "must specify at least one non-empty shape per design");
|
||||
YYERROR;
|
||||
}
|
||||
@ -808,8 +853,8 @@ block: YSAMPLE STRING YENDSAMPLE
|
||||
YYERROR;
|
||||
}
|
||||
|
||||
++num_mandatory;
|
||||
if (++time_for_se_check > 1) {
|
||||
++(bison_args->num_mandatory);
|
||||
if (++(bison_args->time_for_se_check) > 1) {
|
||||
if (perform_se_check(bison_args) != 0) {
|
||||
YYERROR;
|
||||
}
|
||||
@ -863,8 +908,8 @@ block: YSAMPLE STRING YENDSAMPLE
|
||||
|
||||
| YELASTIC '(' elist ')'
|
||||
{
|
||||
++num_mandatory;
|
||||
if (++time_for_se_check > 1) {
|
||||
++(bison_args->num_mandatory);
|
||||
if (++(bison_args->time_for_se_check) > 1) {
|
||||
if (perform_se_check(bison_args) != 0) {
|
||||
YYERROR;
|
||||
}
|
||||
@ -970,7 +1015,7 @@ slist_entry: SHAPE shape_def
|
||||
if (isempty (curdes.shape + $1)) {
|
||||
curdes.shape[$1] = $2;
|
||||
if (!isdeepempty(&($2))) {
|
||||
++num_shapespec;
|
||||
++(bison_args->num_shapespec);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
231
src/parsing.c
231
src/parsing.c
@ -24,73 +24,85 @@
|
||||
|
||||
#include "config.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "boxes.h"
|
||||
#include "parsing.h"
|
||||
#include "parser.h"
|
||||
#include "lex.yy.h"
|
||||
#include "tools.h"
|
||||
|
||||
|
||||
/* file name of the config file currently being parsed */
|
||||
char *current_config_file_name = NULL;
|
||||
|
||||
/** file handle of the config file currently being parsed */
|
||||
static FILE *current_config_handle = NULL;
|
||||
|
||||
/** names of config files specified via "parent" */
|
||||
char **parent_configs = NULL;
|
||||
|
||||
/** number of parent config files (size of parent_configs array) */
|
||||
size_t num_parent_configs = 0;
|
||||
|
||||
/** the arguments passed to our current invocation of the parser */
|
||||
static pass_to_bison *current_bison_args = NULL;
|
||||
|
||||
/** the name of the initially specified config file */
|
||||
static const char *first_config_file = NULL;
|
||||
|
||||
/** all parent configs encountered across all parsed config files */
|
||||
static char **parent_configs = NULL;
|
||||
|
||||
/** total number of parent configs (the size of the `parent_configs` array) */
|
||||
static size_t num_parent_configs = 0;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set yyin and current_config_file_name to the config file to be used.
|
||||
* Set yyin to the config file to be used.
|
||||
*
|
||||
* @param bison_args the bison args that we set up in the calling function
|
||||
* @param config_file_path the new file name to set
|
||||
* @return 0 if successful (yyin and current_config_file_name are set)
|
||||
* @param bison_args the bison args that we set up in the calling function (contains config file path)
|
||||
* @return 0 if successful (yyin is set)
|
||||
* != 0 on error (yyin is unmodified)
|
||||
*/
|
||||
static int open_yy_config_file(pass_to_bison *bison_args, const char *config_file_path)
|
||||
static int open_yy_config_file(pass_to_bison *bison_args)
|
||||
{
|
||||
current_config_handle = fopen(config_file_path, "r");
|
||||
current_config_handle = fopen(bison_args->config_file, "r");
|
||||
if (current_config_handle == NULL) {
|
||||
fprintf(stderr, "%s: Couldn't open config file '%s' for input\n", PROJECT, config_file_path);
|
||||
fprintf(stderr, "%s: Couldn't open config file '%s' for input\n", PROJECT, bison_args->config_file);
|
||||
return 1;
|
||||
}
|
||||
current_config_file_name = (char *) config_file_path;
|
||||
yyset_in(current_config_handle, bison_args->lexer_state);
|
||||
// TODO to reset parser, ‘YY_FLUSH_BUFFER’ and BEGIN INITIAL after each change to yyin.
|
||||
// --> should be ok, because we delete the whole buffer at the beginning, but BEGIN INITIAL may make sense
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void print_design_list_header()
|
||||
{
|
||||
char buf[42];
|
||||
sprintf(buf, "%d", anz_designs);
|
||||
|
||||
fprintf(opt.outfile, "%d Available Style%s in \"%s\":\n",
|
||||
anz_designs, anz_designs == 1 ? "" : "s", current_config_file_name);
|
||||
fprintf(opt.outfile, "-----------------------%s",
|
||||
anz_designs == 1 ? "" : "-");
|
||||
for (int i = strlen(current_config_file_name) + strlen(buf); i > 0; --i) {
|
||||
fprintf(opt.outfile, "-");
|
||||
fprintf(opt.outfile, "%d Available Style%s", anz_designs, anz_designs == 1 ? "" : "s");
|
||||
if (num_parent_configs > 0) {
|
||||
fprintf(opt.outfile, ":\n");
|
||||
fprintf(opt.outfile, "-----------------%s", anz_designs == 1 ? "" : "-");
|
||||
for (int i = strlen(buf); i > 0; --i) {
|
||||
fprintf(opt.outfile, "-");
|
||||
}
|
||||
fprintf(opt.outfile, "\n\n");
|
||||
fprintf(opt.outfile, "Configuration Files:\n");
|
||||
fprintf(opt.outfile, " - %s\n", first_config_file);
|
||||
for (size_t i = 0; i < num_parent_configs; i++) {
|
||||
fprintf(opt.outfile, " - %s (parent)\n", parent_configs[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(opt.outfile, " in \"%s\":\n", first_config_file);
|
||||
fprintf(opt.outfile, "-----------------------%s", anz_designs == 1 ? "" : "-");
|
||||
for (int i = strlen(first_config_file) + strlen(buf); i > 0; --i) {
|
||||
fprintf(opt.outfile, "-");
|
||||
}
|
||||
}
|
||||
fprintf(opt.outfile, "\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Print configuration file parser errors.
|
||||
* @param bison_args pointer to the parser arguments
|
||||
@ -104,9 +116,7 @@ int yyerror(pass_to_bison *bison_args, const char *fmt, ...)
|
||||
va_start (ap, fmt);
|
||||
|
||||
pass_to_bison *bargs = bison_args ? bison_args : current_bison_args;
|
||||
fprintf(stderr, "%s: %s: line %d: ", PROJECT,
|
||||
current_config_file_name ? current_config_file_name : "(null)",
|
||||
yyget_lineno(bargs->lexer_state));
|
||||
fprintf(stderr, "%s: %s: line %d: ", PROJECT, bargs->config_file, yyget_lineno(bargs->lexer_state));
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputc('\n', stderr);
|
||||
|
||||
@ -117,24 +127,54 @@ int yyerror(pass_to_bison *bison_args, const char *fmt, ...)
|
||||
|
||||
|
||||
|
||||
static design_t *parse_config_file(const char *config_file, size_t *r_num_designs)
|
||||
static pass_to_bison new_bison_args(const char *config_file)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Parsing Config File %s ...\n", config_file);
|
||||
#endif
|
||||
|
||||
pass_to_bison bison_args;
|
||||
bison_args.designs = NULL;
|
||||
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;
|
||||
bison_args.skipping = 0;
|
||||
bison_args.speeding = 0;
|
||||
bison_args.parent_configs = NULL;
|
||||
bison_args.num_parent_configs = 0;
|
||||
bison_args.lexer_state = NULL;
|
||||
return bison_args;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static pass_to_flex new_flex_extra_data(pass_to_bison *bison_args)
|
||||
{
|
||||
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);
|
||||
return flex_extra_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static pass_to_bison parse_config_file(const char *config_file)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Parsing Config File %s ...\n", config_file);
|
||||
#endif
|
||||
|
||||
pass_to_bison bison_args = new_bison_args(config_file);
|
||||
pass_to_flex flex_extra_data = new_flex_extra_data(&bison_args);
|
||||
current_bison_args = &bison_args;
|
||||
|
||||
yylex_init (&(bison_args.lexer_state));
|
||||
int rc = open_yy_config_file(&bison_args, config_file);
|
||||
yylex_init_extra(&flex_extra_data, &(bison_args.lexer_state));
|
||||
int rc = open_yy_config_file(&bison_args);
|
||||
if (rc) {
|
||||
return NULL;
|
||||
return new_bison_args(config_file);
|
||||
}
|
||||
inflate_inbuf(bison_args.lexer_state, config_file);
|
||||
rc = yyparse(&bison_args);
|
||||
@ -146,19 +186,126 @@ static design_t *parse_config_file(const char *config_file, size_t *r_num_design
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
return NULL;
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "yyparse() returned %d\n", rc);
|
||||
#endif
|
||||
return new_bison_args(config_file);
|
||||
}
|
||||
*r_num_designs = bison_args.num_designs;
|
||||
return bison_args.designs;
|
||||
return bison_args;
|
||||
}
|
||||
|
||||
|
||||
|
||||
design_t *parse_config_files(const char *first_config_file, size_t *r_num_designs)
|
||||
static int designs_contain(design_t *designs, size_t num_designs, design_t adesign)
|
||||
{
|
||||
// TODO much code
|
||||
int result = adesign.name == NULL; /* broken records count as "present", so we don't copy them */
|
||||
if (designs != NULL && num_designs > 0 && adesign.name != NULL) {
|
||||
for (size_t d = 0; d < num_designs; d++) {
|
||||
if (strcasecmp(designs[d].name, adesign.name) == 0) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return parse_config_file(first_config_file, r_num_designs);
|
||||
|
||||
|
||||
static int record_parent_config_files(pass_to_bison *bison_args)
|
||||
{
|
||||
if (bison_args->num_parent_configs > 0) {
|
||||
for (int parent_idx = bison_args->num_parent_configs - 1; parent_idx >= 0; parent_idx--) {
|
||||
char *parent_file = bison_args->parent_configs[parent_idx];
|
||||
int is_new = !array_contains(parent_configs, num_parent_configs, parent_file);
|
||||
if (is_new) {
|
||||
parent_configs = (char **) realloc(parent_configs, (num_parent_configs + 1) * sizeof(char *));
|
||||
if (parent_configs == NULL) {
|
||||
return 1;
|
||||
}
|
||||
parent_configs[num_parent_configs] = parent_file;
|
||||
++num_parent_configs;
|
||||
}
|
||||
}
|
||||
}
|
||||
BFREE(bison_args->parent_configs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int copy_designs(pass_to_bison *bison_args, design_t **r_result, size_t *r_num_designs)
|
||||
{
|
||||
if (bison_args->num_designs > 0) {
|
||||
if (*r_result == NULL) {
|
||||
*r_result = bison_args->designs;
|
||||
*r_num_designs = bison_args->num_designs;
|
||||
}
|
||||
else {
|
||||
for (size_t d = 0; d < bison_args->num_designs; d++) {
|
||||
if (!designs_contain(*r_result, *r_num_designs, bison_args->designs[d])) {
|
||||
*r_result = (design_t *) realloc(*r_result, (*r_num_designs + 1) * sizeof(design_t));
|
||||
if (*r_result == NULL) {
|
||||
perror(PROJECT);
|
||||
return 1;
|
||||
}
|
||||
memcpy(*r_result + *r_num_designs, bison_args->designs + d, sizeof(design_t));
|
||||
(*r_num_designs)++;
|
||||
}
|
||||
}
|
||||
BFREE(bison_args->designs);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
design_t *parse_config_files(const char *p_first_config_file, size_t *r_num_designs)
|
||||
{
|
||||
size_t parents_parsed = -1; /** how many parent config files have already been parsed */
|
||||
|
||||
design_t *result = NULL;
|
||||
*r_num_designs = 0;
|
||||
|
||||
first_config_file = p_first_config_file;
|
||||
const char *config_file = p_first_config_file;
|
||||
do {
|
||||
pass_to_bison bison_args = parse_config_file(config_file);
|
||||
++parents_parsed;
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "bison_args returned: "
|
||||
".num_parent_configs=%d, .parent_configs=%p, .num_designs=%d, .designs=%p\n",
|
||||
(int) bison_args.num_parent_configs, bison_args.parent_configs,
|
||||
(int) bison_args.num_designs, bison_args.designs);
|
||||
#endif
|
||||
|
||||
if (record_parent_config_files(&bison_args) != 0) {
|
||||
perror(PROJECT);
|
||||
return NULL;
|
||||
}
|
||||
if (copy_designs(&bison_args, &result, r_num_designs) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "design count raised to: %d\n", (int) *r_num_designs);
|
||||
#endif
|
||||
if (parents_parsed < num_parent_configs) {
|
||||
config_file = parent_configs[parents_parsed];
|
||||
}
|
||||
} while (parents_parsed < num_parent_configs);
|
||||
|
||||
if (*r_num_designs == 0) {
|
||||
if (opt.design_choice_by_user) {
|
||||
fprintf (stderr, "%s: unknown box design -- %s\n", PROJECT, (char *) opt.design);
|
||||
}
|
||||
else {
|
||||
fprintf (stderr, "%s: no valid designs found\n", PROJECT);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,20 +28,8 @@
|
||||
#include "parser.h"
|
||||
|
||||
|
||||
/** file name of config file used */
|
||||
extern char *config_file_name;
|
||||
|
||||
/** names of config files specified via "parent" */
|
||||
extern char **parent_configs;
|
||||
|
||||
/** number of parent config files (size of parent_configs array) */
|
||||
extern size_t num_parent_configs;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Print the header for the design list output, which includes the file name.
|
||||
* TODO what if more file names used?
|
||||
* Print the header for the design list output, which includes the file name(s).
|
||||
*/
|
||||
void print_design_list_header();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user