mirror of
https://github.com/ascii-boxes/boxes.git
synced 2025-01-31 09:59:15 +01:00
Add 'parent' keyword to parser/lexer #5
Also major parser/lexer rework to support being called multiple times. Switch to reentrant and parameterizable parser.
This commit is contained in:
parent
425d354bc0
commit
9315e62528
23
src/Makefile
23
src/Makefile
@ -26,13 +26,13 @@ OUT_DIR = ../out
|
||||
SRC_DIR = ../src
|
||||
VPATH = $(SRC_DIR):$(SRC_DIR)/misc
|
||||
|
||||
GEN_HDR = parser.h boxes.h
|
||||
GEN_HDR = parser.h boxes.h lex.yy.h
|
||||
GEN_SRC = parser.c lex.yy.c
|
||||
GEN_FILES = $(GEN_SRC) $(GEN_HDR)
|
||||
ORIG_HDRCL = boxes.in.h config.h
|
||||
ORIG_HDR = $(ORIG_HDRCL) discovery.h generate.h lexer.h regulex.h remove.h shape.h tools.h unicode.h
|
||||
ORIG_HDR = $(ORIG_HDRCL) discovery.h generate.h lexer.h parsing.h regulex.h remove.h shape.h tools.h unicode.h
|
||||
ORIG_GEN = lexer.l parser.y
|
||||
ORIG_NORM = boxes.c discovery.c generate.c regulex.c remove.c shape.c tools.c unicode.c
|
||||
ORIG_NORM = boxes.c discovery.c generate.c parsing.c regulex.c remove.c shape.c tools.c unicode.c
|
||||
ORIG_SRC = $(ORIG_GEN) $(ORIG_NORM)
|
||||
ORIG_FILES = $(ORIG_SRC) $(ORIG_HDR)
|
||||
|
||||
@ -81,14 +81,12 @@ flags_:
|
||||
@echo Please call make from the top level directory.
|
||||
exit 1
|
||||
|
||||
parser.c parser.h: parser.y boxes.h | check_dir
|
||||
$(YACC) -o parser.c -d $<
|
||||
parser.c parser.h: parser.y lex.yy.h | check_dir
|
||||
$(YACC) --warnings=all --verbose --defines=parser.h --output=parser.c $<
|
||||
cpp -I. -I$(SRC_DIR) -P parser.c parser.p
|
||||
|
||||
lex.yy.c: lexer.l boxes.h | check_dir
|
||||
$(LEX) -t $< > lexer.tmp.c
|
||||
echo '#include "config.h"' > lex.yy.c
|
||||
cat lexer.tmp.c >> lex.yy.c
|
||||
rm lexer.tmp.c
|
||||
lex.yy.c lex.yy.h: lexer.l | check_dir
|
||||
$(LEX) --header-file=lex.yy.h $<
|
||||
|
||||
boxes.o: boxes.c boxes.h discovery.h regulex.h shape.h tools.h unicode.h generate.h remove.h config.h | check_dir
|
||||
discovery.o: discovery.c discovery.h boxes.h tools.h config.h | check_dir
|
||||
@ -96,11 +94,12 @@ 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
|
||||
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
|
||||
parser.o: parser.c parser.h tools.h shape.h lexer.h config.h | check_dir
|
||||
lex.yy.o: lex.yy.c parser.h tools.h shape.h lexer.h config.h | check_dir
|
||||
parser.o: parser.c boxes.h lex.yy.h parser.h parsing.h tools.h shape.h discovery.h config.h | check_dir
|
||||
lex.yy.o: lex.yy.c parser.h boxes.h parsing.h tools.h shape.h config.h | check_dir
|
||||
|
||||
package: $(BOXES_EXECUTABLE_NAME)
|
||||
if [ -z "$(PKG_NAME)" ] ; then exit 1 ; fi
|
||||
|
71
src/boxes.c
71
src/boxes.c
@ -39,30 +39,22 @@
|
||||
#include "tools.h"
|
||||
#include "discovery.h"
|
||||
#include "generate.h"
|
||||
#include "parsing.h"
|
||||
#include "regulex.h"
|
||||
#include "remove.h"
|
||||
#include "unicode.h"
|
||||
|
||||
|
||||
extern char *optarg; /* for getopt() */
|
||||
extern int optind, opterr, optopt; /* for getopt() */
|
||||
|
||||
|
||||
|
||||
/* _\|/_
|
||||
(o o)
|
||||
+----oOO-{_}-OOo------------------------------------------------------------+
|
||||
| G l o b a l V a r i a b l e s |
|
||||
+--------------------------------------------------------------------------*/
|
||||
|
||||
extern int yyparse();
|
||||
extern FILE *yyin; /* lex input file */
|
||||
|
||||
char *yyfilename = NULL; /* file name of config file used */
|
||||
extern char *optarg; /* for getopt() */
|
||||
extern int optind, opterr, optopt; /* for getopt() */
|
||||
|
||||
design_t *designs = NULL; /* available box designs */
|
||||
|
||||
int design_idx = 0; /* anz_designs-1 */
|
||||
int anz_designs = 0; /* no of designs after parsing */
|
||||
|
||||
opt_t opt; /* command line options */
|
||||
@ -77,29 +69,6 @@ input_t input = INPUT_INITIALIZER; /* input lines */
|
||||
| F u n c t i o n s |
|
||||
+--------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static int open_yy_config_file(const char *config_file_name)
|
||||
/*
|
||||
* Set yyin and yyfilename to the config file to be used.
|
||||
*
|
||||
* RETURNS: == 0 success (yyin and yyfilename are set)
|
||||
* != 0 error (yyin is unmodified)
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
{
|
||||
FILE *new_yyin = fopen(config_file_name, "r");
|
||||
if (new_yyin == NULL) {
|
||||
fprintf(stderr, "%s: Couldn't open config file '%s' for input\n", PROJECT, config_file_name);
|
||||
return 1;
|
||||
}
|
||||
yyfilename = (char *) config_file_name;
|
||||
yyin = new_yyin;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void usage(FILE *st)
|
||||
/*
|
||||
* Print usage information on stream st.
|
||||
@ -916,9 +885,8 @@ static int list_styles()
|
||||
|
||||
else {
|
||||
design_t **list; /* temp list for sorting */
|
||||
char buf[42];
|
||||
|
||||
list = (design_t **) calloc(design_idx + 1, sizeof(design_t *));
|
||||
list = (design_t **) calloc(anz_designs, sizeof(design_t *));
|
||||
if (list == NULL) {
|
||||
perror(PROJECT);
|
||||
return 1;
|
||||
@ -927,19 +895,10 @@ static int list_styles()
|
||||
for (i = 0; i < anz_designs; ++i) {
|
||||
list[i] = &(designs[i]);
|
||||
}
|
||||
qsort(list, design_idx + 1, sizeof(design_t *), style_sort);
|
||||
|
||||
sprintf(buf, "%d", anz_designs);
|
||||
qsort(list, anz_designs, sizeof(design_t *), style_sort);
|
||||
|
||||
if (!opt.q) {
|
||||
fprintf(opt.outfile, "%d Available Style%s in \"%s\":\n",
|
||||
anz_designs, anz_designs == 1 ? "" : "s", yyfilename);
|
||||
fprintf(opt.outfile, "-----------------------%s",
|
||||
anz_designs == 1 ? "" : "-");
|
||||
for (i = strlen(yyfilename) + strlen(buf); i > 0; --i) {
|
||||
fprintf(opt.outfile, "-");
|
||||
}
|
||||
fprintf(opt.outfile, "\n\n");
|
||||
print_design_list_header();
|
||||
}
|
||||
for (i = 0; i < anz_designs; ++i) {
|
||||
if (opt.q) {
|
||||
@ -1366,27 +1325,19 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Parse config file, then reset design pointer
|
||||
* Parse config file(s), then reset design pointer
|
||||
*/
|
||||
char *config_file = discover_config_file(0);
|
||||
if (config_file == NULL) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (opt.cld == NULL) {
|
||||
yyin = stdin;
|
||||
rc = open_yy_config_file(config_file);
|
||||
if (rc) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Parsing Config File %s ...\n", config_file);
|
||||
#endif
|
||||
if (opt.cld == NULL) {
|
||||
rc = yyparse();
|
||||
if (rc) {
|
||||
size_t r_num_designs = 0;
|
||||
designs = parse_config_files(config_file, &r_num_designs);
|
||||
if (designs == NULL) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
anz_designs = (int) r_num_designs;
|
||||
}
|
||||
else {
|
||||
rc = build_design(&designs, opt.cld);
|
||||
|
@ -115,35 +115,30 @@ typedef struct {
|
||||
|
||||
extern design_t *designs;
|
||||
extern int anz_designs;
|
||||
extern int design_idx;
|
||||
|
||||
|
||||
extern int tjlineno; /* config file line counter */
|
||||
extern char *yyfilename; /* name of config file */
|
||||
|
||||
|
||||
typedef struct { /* Command line options: */
|
||||
int l; /* list available designs */
|
||||
char *f; /* the string specified as argument to -f ; config file path */
|
||||
int mend; /* 1 if -m is given, 2 in 2nd loop */
|
||||
int q; /* special handling of web UI needs */
|
||||
int r; /* remove box from input */
|
||||
int tabstop; /* tab stop distance */
|
||||
char tabexp; /* tab expansion mode (for leading tabs) */
|
||||
int padding[ANZ_SIDES]; /* in spaces or lines resp. */
|
||||
design_t *design; /* currently used box design */
|
||||
int design_choice_by_user; /* true if design was chosen by user */
|
||||
char *cld; /* commandline design definition, -c */
|
||||
long reqwidth; /* requested box width (-s) */
|
||||
long reqheight; /* requested box height (-s) */
|
||||
char valign; /* text position inside box */
|
||||
char halign; /* ( h[lcr]v[tcb] ) */
|
||||
char indentmode; /* 'b', 't', 'n', or '\0' */
|
||||
char justify; /* 'l', 'c', 'r', or '\0' */
|
||||
int killblank; /* -1 if not set */
|
||||
char *encoding; /* character encoding override for input and output text */
|
||||
FILE *infile; /* where we get our input */
|
||||
FILE *outfile; /* where we put our output */
|
||||
int l; /** list available designs */
|
||||
char *f; /** the string specified as argument to -f ; config file path */
|
||||
int mend; /** 1 if -m is given, 2 in 2nd loop */
|
||||
int q; /** special handling of web UI needs */
|
||||
int r; /** remove box from input */
|
||||
int tabstop; /** tab stop distance */
|
||||
char tabexp; /** tab expansion mode (for leading tabs) */
|
||||
int padding[ANZ_SIDES]; /** in spaces or lines resp. */
|
||||
design_t *design; /** currently used box design */
|
||||
int design_choice_by_user; /** true if design was chosen by user */
|
||||
char *cld; /** commandline design definition, -c */
|
||||
long reqwidth; /** requested box width (-s) */
|
||||
long reqheight; /** requested box height (-s) */
|
||||
char valign; /** text position inside box */
|
||||
char halign; /** ( h[lcr]v[tcb] ) */
|
||||
char indentmode; /** 'b', 't', 'n', or '\0' */
|
||||
char justify; /** 'l', 'c', 'r', or '\0' */
|
||||
int killblank; /** -1 if not set */
|
||||
char *encoding; /** character encoding override for input and output text */
|
||||
FILE *infile; /** where we get our input */
|
||||
FILE *outfile; /** where we put our output */
|
||||
} opt_t;
|
||||
|
||||
extern opt_t opt;
|
||||
|
47
src/lexer.h
47
src/lexer.h
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License, version 2, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Export symbols used by the parser files only
|
||||
*/
|
||||
|
||||
#ifndef LEXER_H
|
||||
#define LEXER_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 "\"~'`!@%&*=:;<>?/|.\\"
|
||||
|
||||
|
||||
int yylex(); /* defined in lex.yy.c */
|
||||
|
||||
void begin_speedmode();
|
||||
|
||||
void chg_strdelims (const char asdel, const char asesc);
|
||||
|
||||
extern int speeding;
|
||||
|
||||
|
||||
#endif /*LEXER_H*/
|
||||
|
||||
/*EOF*/ /* vim: set sw=4: */
|
207
src/lexer.l
207
src/lexer.l
@ -1,4 +1,4 @@
|
||||
%{
|
||||
%top{
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
@ -24,6 +24,28 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void begin_speedmode();
|
||||
|
||||
|
||||
void chg_strdelims (const char asdel, const char asesc);
|
||||
|
||||
|
||||
/**
|
||||
* User-defined initializations for the lexer.
|
||||
*
|
||||
* Since this scanner must use REJECT in order to be able to process the string delimiter commands, it cannot
|
||||
* 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 configfile the path to the config file we are reading
|
||||
*/
|
||||
void inflate_inbuf(void *scanner, const char *configfile);
|
||||
|
||||
}
|
||||
|
||||
%{
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@ -32,59 +54,59 @@
|
||||
#include "boxes.h"
|
||||
#undef FILE_LEXER_L
|
||||
#include "tools.h"
|
||||
#include "parsing.h"
|
||||
#include "parser.h"
|
||||
#include "lexer.h"
|
||||
|
||||
|
||||
|
||||
#define LEX_MAX_WARN 3 /* number of lex errors per design */
|
||||
|
||||
|
||||
int tjlineno = 1;
|
||||
|
||||
static int yyerrcnt = 0;
|
||||
|
||||
/* the currently active string delimiter character */
|
||||
static char sdel = '\"';
|
||||
|
||||
/* the currently active string escape character */
|
||||
static char sesc = '\\';
|
||||
|
||||
|
||||
/*
|
||||
* User-defined initializations for the lexer
|
||||
*/
|
||||
static void inflate_inbuf();
|
||||
#define YY_USER_INIT inflate_inbuf()
|
||||
|
||||
%}
|
||||
|
||||
|
||||
%option 8bit
|
||||
%option bison-bridge
|
||||
%option case-insensitive
|
||||
%option ecs
|
||||
%option never-interactive
|
||||
%option nodefault
|
||||
%option noinput
|
||||
%option nounput
|
||||
%option noyywrap
|
||||
%option never-interactive
|
||||
%option caseless
|
||||
%option noinput
|
||||
%option noyylineno
|
||||
%option reentrant
|
||||
%option warn
|
||||
%option yylineno
|
||||
|
||||
|
||||
%x SAMPLE
|
||||
%x SPEEDMODE
|
||||
%x DELWORD
|
||||
%x PARENT
|
||||
%s SHAPES
|
||||
%s ELASTIC
|
||||
|
||||
|
||||
PWORD [a-zA-ZäöüÄÖÜ][a-zA-Z0-9\-_üäöÜÄÖß]*
|
||||
PWHITE [\n \r\t]
|
||||
PBOX Box
|
||||
SDELIM [\"~\'`!@\%\&\*=:;<>\?/|\.\\]
|
||||
PWORD [a-zA-ZäöüÄÖÜ][a-zA-Z0-9\-_üäöÜÄÖß]*
|
||||
PWHITE [\n \r\t]
|
||||
PBOX Box
|
||||
SDELIM [\"~\'`!@\%\&\*=:;<>\?/|\.\\]
|
||||
PPARENT parent
|
||||
PFILENAME [^\r\n]+
|
||||
|
||||
|
||||
%%
|
||||
|
||||
|
||||
|
||||
<DELWORD,SHAPES,ELASTIC,INITIAL>[ \r\t] /* ignore whitespace */
|
||||
|
||||
<DELWORD,SHAPES,ELASTIC,INITIAL>\n ++tjlineno;
|
||||
<DELWORD,SHAPES,ELASTIC,INITIAL>\n {}
|
||||
|
||||
|
||||
<DELWORD>[^ \t\r\n]+ {
|
||||
@ -94,8 +116,8 @@ SDELIM [\"~\'`!@\%\&\*=:;<>\?/|\.\\]
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYDELWOR: %s -- STATE INITIAL", yytext);
|
||||
#endif
|
||||
yylval.s = (char *) strdup (yytext);
|
||||
if (yylval.s == NULL) {
|
||||
yylval->s = (char *) strdup (yytext);
|
||||
if (yylval->s == NULL) {
|
||||
perror (PROJECT);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@ -118,12 +140,12 @@ SDELIM [\"~\'`!@\%\&\*=:;<>\?/|\.\\]
|
||||
REJECT; /* that was not our delimiter */
|
||||
}
|
||||
|
||||
yylval.s = (char *) strdup (yytext + 1);
|
||||
if (yylval.s == NULL) {
|
||||
yylval->s = (char *) strdup (yytext + 1);
|
||||
if (yylval->s == NULL) {
|
||||
perror (PROJECT);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
p = yylval.s;
|
||||
p = yylval->s;
|
||||
|
||||
while (*p) {
|
||||
if (*p == sesc) {
|
||||
@ -135,9 +157,9 @@ SDELIM [\"~\'`!@\%\&\*=:;<>\?/|\.\\]
|
||||
}
|
||||
else if (*p == sdel) {
|
||||
*p = '\0';
|
||||
yyless ((p-yylval.s)+2+qcnt); /* string plus quotes */
|
||||
yyless ((p-yylval->s)+2+qcnt); /* string plus quotes */
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STRING: \"%s\"", yylval.s);
|
||||
fprintf (stderr, "\n STRING: \"%s\"", yylval->s);
|
||||
#endif
|
||||
return STRING;
|
||||
}
|
||||
@ -145,11 +167,40 @@ SDELIM [\"~\'`!@\%\&\*=:;<>\?/|\.\\]
|
||||
++p;
|
||||
}
|
||||
if (yyerrcnt++ < 5)
|
||||
yyerror ("Unterminated String -- %s", yytext);
|
||||
yyerror(NULL, "Unterminated String -- %s", yytext);
|
||||
return YUNREC;
|
||||
}
|
||||
|
||||
|
||||
{PPARENT} {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYPARENT: %s", yytext);
|
||||
#endif
|
||||
BEGIN PARENT;
|
||||
return YPARENT;
|
||||
}
|
||||
|
||||
<PARENT>{PFILENAME} {
|
||||
char *p = yytext;
|
||||
while (*p == ' ' || *p == '\t') {
|
||||
++p;
|
||||
}
|
||||
yylval->s = (char *) strdup (p);
|
||||
p = yylval->s + strlen(yylval->s) - 1;
|
||||
while ((*p == ' ' || *p == '\t') && p >= yylval->s) {
|
||||
*p-- = '\0';
|
||||
}
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STRING: \"%s\"", yylval->s);
|
||||
#endif
|
||||
BEGIN INITIAL;
|
||||
return STRING;
|
||||
}
|
||||
|
||||
<PARENT>\n {
|
||||
BEGIN INITIAL;
|
||||
}
|
||||
|
||||
|
||||
Sample {
|
||||
#ifdef LEXER_DEBUG
|
||||
@ -161,7 +212,6 @@ Sample {
|
||||
|
||||
|
||||
<SAMPLE>\n {
|
||||
++tjlineno;
|
||||
if (yyleng > 1)
|
||||
yymore();
|
||||
}
|
||||
@ -175,8 +225,8 @@ Sample {
|
||||
--p; /* skip trailing whitespace */
|
||||
p -= 2; /* almost skip "ends" statement */
|
||||
*p = '\0'; /* p now points to 'n' */
|
||||
yylval.s = (char *) strdup (yytext);
|
||||
if (yylval.s == NULL) {
|
||||
yylval->s = (char *) strdup (yytext);
|
||||
if (yylval->s == NULL) {
|
||||
perror (PROJECT);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@ -185,20 +235,20 @@ 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 */
|
||||
btrim (yylval.s, &len);
|
||||
yylval->s[len] = '\n'; /* replace 'e' with newline */
|
||||
btrim (yylval->s, &len);
|
||||
if (len > 0) {
|
||||
strcat (yylval.s, "\n"); /* memory was allocated with strdup */
|
||||
strcat (yylval->s, "\n"); /* memory was allocated with strdup */
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STRING: \"%s\" -- STATE INITIAL", yylval.s);
|
||||
fprintf (stderr, "\n STRING: \"%s\" -- STATE INITIAL", yylval->s);
|
||||
#endif
|
||||
BEGIN INITIAL;
|
||||
return STRING;
|
||||
}
|
||||
else {
|
||||
if (yyerrcnt++ < 5)
|
||||
yyerror ("SAMPLE block must not be empty");
|
||||
BFREE (yylval.s);
|
||||
yyerror(NULL, "SAMPLE block must not be empty");
|
||||
BFREE (yylval->s);
|
||||
return YUNREC;
|
||||
}
|
||||
}
|
||||
@ -246,26 +296,26 @@ Padding { return YPADDING; }
|
||||
End { return YEND; }
|
||||
To { return YTO; }
|
||||
With { return YWITH; }
|
||||
Global { yylval.c = 'g'; return YRXPFLAG; }
|
||||
Once { yylval.c = 'o'; return YRXPFLAG; }
|
||||
Global { yylval->c = 'g'; return YRXPFLAG; }
|
||||
Once { yylval->c = 'o'; return YRXPFLAG; }
|
||||
|
||||
|
||||
<SHAPES,ELASTIC>nw { yylval.shape = NW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>nnw { yylval.shape = NNW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>n { yylval.shape = N; return SHAPE; }
|
||||
<SHAPES,ELASTIC>nne { yylval.shape = NNE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>ne { yylval.shape = NE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>ene { yylval.shape = ENE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>e { yylval.shape = E; return SHAPE; }
|
||||
<SHAPES,ELASTIC>ese { yylval.shape = ESE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>se { yylval.shape = SE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>sse { yylval.shape = SSE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>s { yylval.shape = S; return SHAPE; }
|
||||
<SHAPES,ELASTIC>ssw { yylval.shape = SSW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>sw { yylval.shape = SW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>wsw { yylval.shape = WSW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>w { yylval.shape = W; return SHAPE; }
|
||||
<SHAPES,ELASTIC>wnw { yylval.shape = WNW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>nw { yylval->shape = NW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>nnw { yylval->shape = NNW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>n { yylval->shape = N; return SHAPE; }
|
||||
<SHAPES,ELASTIC>nne { yylval->shape = NNE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>ne { yylval->shape = NE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>ene { yylval->shape = ENE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>e { yylval->shape = E; return SHAPE; }
|
||||
<SHAPES,ELASTIC>ese { yylval->shape = ESE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>se { yylval->shape = SE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>sse { yylval->shape = SSE; return SHAPE; }
|
||||
<SHAPES,ELASTIC>s { yylval->shape = S; return SHAPE; }
|
||||
<SHAPES,ELASTIC>ssw { yylval->shape = SSW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>sw { yylval->shape = SW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>wsw { yylval->shape = WSW; return SHAPE; }
|
||||
<SHAPES,ELASTIC>w { yylval->shape = W; return SHAPE; }
|
||||
<SHAPES,ELASTIC>wnw { yylval->shape = WNW; return SHAPE; }
|
||||
|
||||
<ELASTIC>\) {
|
||||
#ifdef LEXER_DEBUG
|
||||
@ -291,8 +341,8 @@ author|designer|tags|created|revision|revdate|indent {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nKEYWORD: %s", yytext);
|
||||
#endif
|
||||
yylval.s = (char *) strdup (yytext);
|
||||
if (yylval.s == NULL) {
|
||||
yylval->s = (char *) strdup (yytext);
|
||||
if (yylval->s == NULL) {
|
||||
perror (PROJECT);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@ -316,8 +366,8 @@ Delimiter|Delim {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n WORD: %s", yytext);
|
||||
#endif
|
||||
yylval.s = (char *) strdup (yytext);
|
||||
if (yylval.s == NULL) {
|
||||
yylval->s = (char *) strdup (yytext);
|
||||
if (yylval->s == NULL) {
|
||||
perror (PROJECT);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@ -329,7 +379,7 @@ Delimiter|Delim {
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\nYNUMBER: %s", yytext);
|
||||
#endif
|
||||
yylval.num = atoi (yytext);
|
||||
yylval->num = atoi (yytext);
|
||||
return YNUMBER;
|
||||
}
|
||||
|
||||
@ -352,7 +402,7 @@ Delimiter|Delim {
|
||||
|
||||
. {
|
||||
if (yyerrcnt++ < LEX_MAX_WARN)
|
||||
yyerror ("Unrecognized input char \'%s\'", yytext);
|
||||
yyerror(NULL, "Unrecognized input char \'%s\'", yytext);
|
||||
return YUNREC;
|
||||
}
|
||||
|
||||
@ -366,7 +416,7 @@ Delimiter|Delim {
|
||||
BEGIN INITIAL;
|
||||
}
|
||||
|
||||
<SPEEDMODE>\n ++tjlineno;
|
||||
<SPEEDMODE>\n {}
|
||||
|
||||
<SPEEDMODE>. /* ignore anything else */
|
||||
|
||||
@ -374,35 +424,31 @@ Delimiter|Delim {
|
||||
%%
|
||||
|
||||
|
||||
static void inflate_inbuf()
|
||||
/*
|
||||
* User-defined initializations for the lexer.
|
||||
*
|
||||
* Since this scanner must use REJECT in order to be able to process the
|
||||
* string delimiter commands, it cannot 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.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
/* 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)
|
||||
{
|
||||
struct stat sinf;
|
||||
|
||||
if (stat(yyfilename, &sinf)) {
|
||||
if (stat(configfile, &sinf)) {
|
||||
perror (PROJECT);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
yy_delete_buffer (YY_CURRENT_BUFFER);
|
||||
yy_switch_to_buffer (yy_create_buffer (yyin, sinf.st_size+10));
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void begin_speedmode()
|
||||
void begin_speedmode(void *scanner)
|
||||
{
|
||||
#ifdef LEXER_DEBUG
|
||||
fprintf (stderr, "\n STATUS: begin_speedmode() -- STATE SPEEDMODE");
|
||||
#endif
|
||||
struct yyguts_t *yyg = (struct yyguts_t *) scanner;
|
||||
BEGIN SPEEDMODE;
|
||||
}
|
||||
|
||||
@ -418,5 +464,4 @@ void chg_strdelims (const char asesc, const char asdel)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*EOF*/ /* vim: set cindent sw=4: */
|
||||
|
560
src/parser.y
560
src/parser.y
File diff suppressed because it is too large
Load Diff
166
src/parsing.c
Normal file
166
src/parsing.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License, version 2, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Configuration file parsing
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "boxes.h"
|
||||
#include "parsing.h"
|
||||
#include "parser.h"
|
||||
#include "lex.yy.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;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set yyin and current_config_file_name 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)
|
||||
* != 0 on error (yyin is unmodified)
|
||||
*/
|
||||
static int open_yy_config_file(pass_to_bison *bison_args, const char *config_file_path)
|
||||
{
|
||||
current_config_handle = fopen(config_file_path, "r");
|
||||
if (current_config_handle == NULL) {
|
||||
fprintf(stderr, "%s: Couldn't open config file '%s' for input\n", PROJECT, config_file_path);
|
||||
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, "\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Print configuration file parser errors.
|
||||
* @param bison_args pointer to the parser arguments
|
||||
* @param fmt a format string for `vfprintf()`, followed by the arguments
|
||||
* @return 0
|
||||
*/
|
||||
int yyerror(pass_to_bison *bison_args, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
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));
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputc('\n', stderr);
|
||||
|
||||
va_end (ap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static design_t *parse_config_file(const char *config_file, size_t *r_num_designs)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Parsing Config File %s ...\n", config_file);
|
||||
#endif
|
||||
|
||||
// TODO the parser reallocs the global designs array, do this with module-local vars
|
||||
|
||||
pass_to_bison bison_args;
|
||||
bison_args.designs = NULL;
|
||||
bison_args.num_designs = 0;
|
||||
bison_args.design_idx = 0;
|
||||
bison_args.lexer_state = NULL;
|
||||
current_bison_args = &bison_args;
|
||||
|
||||
yylex_init (&(bison_args.lexer_state));
|
||||
int rc = open_yy_config_file(&bison_args, config_file);
|
||||
if (rc) {
|
||||
return NULL;
|
||||
}
|
||||
inflate_inbuf(bison_args.lexer_state, config_file);
|
||||
rc = yyparse(&bison_args);
|
||||
yylex_destroy(bison_args.lexer_state);
|
||||
|
||||
if (current_config_handle != NULL) {
|
||||
fclose(current_config_handle);
|
||||
current_config_handle = NULL;
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
return NULL;
|
||||
}
|
||||
*r_num_designs = bison_args.num_designs;
|
||||
return bison_args.designs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
design_t *parse_config_files(const char *first_config_file, size_t *r_num_designs)
|
||||
{
|
||||
// TODO much code
|
||||
|
||||
return parse_config_file(first_config_file, r_num_designs);
|
||||
}
|
||||
|
||||
|
||||
/*EOF*/ /* vim: set sw=4: */
|
70
src/parsing.h
Normal file
70
src/parsing.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License, version 2, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Configuration file parsing
|
||||
*/
|
||||
|
||||
#ifndef PARSING_H
|
||||
#define PARSING_H 1
|
||||
|
||||
#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?
|
||||
*/
|
||||
void print_design_list_header();
|
||||
|
||||
|
||||
/**
|
||||
* Print configuration file parser errors.
|
||||
* @param bison_args pointer to the parser arguments, not used
|
||||
* @param fmt a format string for `vfprintf()`, followed by the arguments
|
||||
* @return 0
|
||||
*/
|
||||
int yyerror(pass_to_bison *bison_args, const char *fmt, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Parse the given config file and all parents.
|
||||
* @param first_config_file the path to the config file (relative or absolute)
|
||||
* @param r_num_designs a return argument that takes the number of design definitions returned from the function.
|
||||
* Will be set to 0 on error
|
||||
* @return the consolidated list of designs parsed, or `NULL` on error (then an error message was alread printed)
|
||||
*/
|
||||
design_t *parse_config_files(const char *first_config_file, size_t *r_num_designs);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*EOF*/ /* vim: set cindent sw=4: */
|
39
src/tools.c
39
src/tools.c
@ -42,45 +42,6 @@
|
||||
|
||||
|
||||
|
||||
int yyerror(const char *fmt, ...)
|
||||
/*
|
||||
* Print configuration file parser errors.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, fmt);
|
||||
|
||||
fprintf(stderr, "%s: %s: line %d: ", PROJECT,
|
||||
yyfilename ? yyfilename : "(null)", tjlineno);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputc('\n', stderr);
|
||||
|
||||
va_end (ap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void regerror(char *msg)
|
||||
/*
|
||||
* Print regular expression andling error messages
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
{
|
||||
fprintf(stderr, "%s: %s: line %d: %s\n",
|
||||
PROJECT, yyfilename ? yyfilename : "(null)",
|
||||
opt.design->current_rule ? opt.design->current_rule->line : 0,
|
||||
msg);
|
||||
errno = EINVAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int strisyes(const char *s)
|
||||
/*
|
||||
* Determine if the string s has a contents indicating "yes".
|
||||
|
@ -45,10 +45,6 @@
|
||||
}
|
||||
|
||||
|
||||
int yyerror(const char *fmt, ...);
|
||||
|
||||
void regerror(char *msg);
|
||||
|
||||
int empty_line(const line_t *line);
|
||||
|
||||
size_t expand_tabs_into(const uint32_t *input_buffer, const int tabstop, uint32_t **text,
|
||||
|
Loading…
Reference in New Issue
Block a user