COMP: add lemon parser and skeleton code
This commit is contained in:
parent
4a6cd8f194
commit
f1ed0a617b
1097
wmake/etc/lempar.c
Normal file
1097
wmake/etc/lempar.c
Normal file
File diff suppressed because it is too large
Load Diff
136
wmake/etc/lempar.c.patch
Normal file
136
wmake/etc/lempar.c.patch
Normal file
@ -0,0 +1,136 @@
|
||||
--- lempar.c.orig 2019-08-30 17:49:01.815549795 +0200
|
||||
+++ lempar.c 2019-09-26 16:09:17.880373536 +0200
|
||||
@@ -251,12 +251,14 @@
|
||||
** Outputs:
|
||||
** None.
|
||||
*/
|
||||
+%namespace_begin
|
||||
void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
|
||||
yyTraceFILE = TraceFILE;
|
||||
yyTracePrompt = zTracePrompt;
|
||||
if( yyTraceFILE==0 ) yyTracePrompt = 0;
|
||||
else if( yyTracePrompt==0 ) yyTraceFILE = 0;
|
||||
}
|
||||
+%namespace_end
|
||||
#endif /* NDEBUG */
|
||||
|
||||
#if defined(YYCOVERAGE) || !defined(NDEBUG)
|
||||
@@ -320,6 +322,7 @@
|
||||
|
||||
/* Initialize a new parser that has already been allocated.
|
||||
*/
|
||||
+%namespace_begin
|
||||
void ParseInit(void *yypRawParser ParseCTX_PDECL){
|
||||
yyParser *yypParser = (yyParser*)yypRawParser;
|
||||
ParseCTX_STORE
|
||||
@@ -344,6 +347,7 @@
|
||||
#if YYSTACKDEPTH>0
|
||||
yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
|
||||
#endif
|
||||
+%namespace_end
|
||||
}
|
||||
|
||||
#ifndef Parse_ENGINEALWAYSONSTACK
|
||||
@@ -359,6 +363,7 @@
|
||||
** A pointer to a parser. This pointer is used in subsequent calls
|
||||
** to Parse and ParseFree.
|
||||
*/
|
||||
+%namespace_begin
|
||||
void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) ParseCTX_PDECL){
|
||||
yyParser *yypParser;
|
||||
yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
|
||||
@@ -368,6 +373,7 @@
|
||||
}
|
||||
return (void*)yypParser;
|
||||
}
|
||||
+%namespace_end
|
||||
#endif /* Parse_ENGINEALWAYSONSTACK */
|
||||
|
||||
|
||||
@@ -427,6 +433,7 @@
|
||||
/*
|
||||
** Clear all secondary memory allocations from the parser
|
||||
*/
|
||||
+%namespace_begin
|
||||
void ParseFinalize(void *p){
|
||||
yyParser *pParser = (yyParser*)p;
|
||||
while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
|
||||
@@ -434,6 +441,7 @@
|
||||
if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
|
||||
#endif
|
||||
}
|
||||
+%namespace_end
|
||||
|
||||
#ifndef Parse_ENGINEALWAYSONSTACK
|
||||
/*
|
||||
@@ -444,6 +452,7 @@
|
||||
** is defined in a %include section of the input grammar) then it is
|
||||
** assumed that the input pointer is never NULL.
|
||||
*/
|
||||
+%namespace_begin
|
||||
void ParseFree(
|
||||
void *p, /* The parser to be deleted */
|
||||
void (*freeProc)(void*) /* Function used to reclaim memory */
|
||||
@@ -454,16 +463,19 @@
|
||||
ParseFinalize(p);
|
||||
(*freeProc)(p);
|
||||
}
|
||||
+%namespace_end
|
||||
#endif /* Parse_ENGINEALWAYSONSTACK */
|
||||
|
||||
/*
|
||||
** Return the peak depth of the stack for a parser.
|
||||
*/
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
+%namespace_begin
|
||||
int ParseStackPeak(void *p){
|
||||
yyParser *pParser = (yyParser*)p;
|
||||
return pParser->yyhwm;
|
||||
}
|
||||
+%namespace_end
|
||||
#endif
|
||||
|
||||
/* This array of booleans keeps track of the parser statement
|
||||
@@ -484,6 +496,7 @@
|
||||
** Return the number of missed state/lookahead combinations.
|
||||
*/
|
||||
#if defined(YYCOVERAGE)
|
||||
+%namespace_begin
|
||||
int ParseCoverage(FILE *out){
|
||||
int stateno, iLookAhead, i;
|
||||
int nMissed = 0;
|
||||
@@ -501,6 +514,7 @@
|
||||
}
|
||||
return nMissed;
|
||||
}
|
||||
+%namespace_end
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -893,6 +907,7 @@
|
||||
** Outputs:
|
||||
** None.
|
||||
*/
|
||||
+%namespace_begin
|
||||
void Parse(
|
||||
void *yyp, /* The parser */
|
||||
int yymajor, /* The major token code number */
|
||||
@@ -1062,11 +1077,13 @@
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
+%namespace_end
|
||||
|
||||
/*
|
||||
** Return the fallback token corresponding to canonical token iToken, or
|
||||
** 0 if iToken has no fallback.
|
||||
*/
|
||||
+%namespace_begin
|
||||
int ParseFallback(int iToken){
|
||||
#ifdef YYFALLBACK
|
||||
if( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ){
|
||||
@@ -1077,3 +1094,4 @@
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
+%namespace_end
|
@ -64,7 +64,7 @@ archTarget := $(shell basename $(WMAKE_BIN))
|
||||
|
||||
.PHONY: all clean message
|
||||
|
||||
all: $(WMAKE_BIN)/wmkdepend$(EXT_EXE) message
|
||||
all: $(WMAKE_BIN)/lemon$(EXT_EXE) $(WMAKE_BIN)/wmkdepend$(EXT_EXE) message
|
||||
|
||||
message:
|
||||
ifneq ($(archHost),$(archTarget))
|
||||
@ -78,6 +78,11 @@ clean:
|
||||
@rm -rf $(WMAKE_BIN) 2>/dev/null
|
||||
@rmdir $(shell dirname $(WMAKE_BIN)) 2>/dev/null || true
|
||||
|
||||
$(WMAKE_BIN)/lemon$(EXT_EXE): lemon.c
|
||||
@mkdir -p $(WMAKE_BIN)
|
||||
$(call QUIET_MESSAGE,lemon,$(<F))
|
||||
$(cc) $(cFLAGS) $(<F) -o $@
|
||||
|
||||
$(WMAKE_BIN)/wmkdep$(EXT_EXE): wmkdep.l
|
||||
@mkdir -p $(WMAKE_BIN)
|
||||
$(call QUIET_MESSAGE,flex,$(<F))
|
||||
|
23
wmake/src/README.txt
Normal file
23
wmake/src/README.txt
Normal file
@ -0,0 +1,23 @@
|
||||
Minimal changes to lemon for C++ integration.
|
||||
|
||||
- New '-e' command line option to define the code extension.
|
||||
By default this is 'c', but with this option can define something
|
||||
like -ecxx etc for using a C++ compiler.
|
||||
|
||||
- New '%namespace' directive. This can be used to embed the 'Parse*'
|
||||
routines into a C++ namespace. The namespace can be anonymous or
|
||||
contain multiple nested namespaces. For example,
|
||||
|
||||
%namespace {}
|
||||
%namespace {ns1::ns2::ns3}
|
||||
|
||||
|
||||
One simple means to encapsulate code is to use an anonymous
|
||||
namespace for the Lemon code and place all C++ interface code with
|
||||
the %code block in the same translation unit.
|
||||
|
||||
This allows good encapsulation without fundamentally changing how
|
||||
Lemon works.
|
||||
|
||||
--
|
||||
2019-09-27
|
5719
wmake/src/lemon.c
Normal file
5719
wmake/src/lemon.c
Normal file
File diff suppressed because it is too large
Load Diff
271
wmake/src/lemon.c.patch
Normal file
271
wmake/src/lemon.c.patch
Normal file
@ -0,0 +1,271 @@
|
||||
--- lemon.c.orig 2019-09-26 14:00:01.572868618 +0200
|
||||
+++ lemon.c 2019-09-27 09:05:08.182250296 +0200
|
||||
@@ -404,6 +404,7 @@
|
||||
struct symbol *errsym; /* The error symbol */
|
||||
struct symbol *wildcard; /* Token that matches anything */
|
||||
char *name; /* Name of the generated parser */
|
||||
+ char *namesp; /* Surrounding namespace for generated parser */
|
||||
char *arg; /* Declaration of the 3th argument to parser */
|
||||
char *ctx; /* Declaration of 2nd argument to constructor */
|
||||
char *tokentype; /* Type of terminal symbols in the parser stack */
|
||||
@@ -1557,6 +1558,23 @@
|
||||
lemon_strcpy(outputDir, z);
|
||||
}
|
||||
|
||||
+/* Remember the name of the code extension (automatically prefix '.')
|
||||
+*/
|
||||
+static char *code_ext = NULL;
|
||||
+static void handle_e_option(char *z){
|
||||
+ code_ext = (char *) malloc( lemonStrlen(z)+2 );
|
||||
+ if( code_ext==0 ){
|
||||
+ fprintf(stderr,"out of memory\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ if(*z == '.'){
|
||||
+ lemon_strcpy(code_ext, z);
|
||||
+ } else {
|
||||
+ code_ext[0] = '.';
|
||||
+ lemon_strcpy(&(code_ext[1]), z);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static char *user_templatename = NULL;
|
||||
static void handle_T_option(char *z){
|
||||
user_templatename = (char *) malloc( lemonStrlen(z)+1 );
|
||||
@@ -1644,6 +1662,7 @@
|
||||
{OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."},
|
||||
{OPT_FSTR, "d", (char*)&handle_d_option, "Output directory. Default '.'"},
|
||||
{OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."},
|
||||
+ {OPT_FSTR, "e", (char*)&handle_e_option, "Output code extension. Default 'c'"},
|
||||
{OPT_FSTR, "f", 0, "Ignored. (Placeholder for -f compiler options.)"},
|
||||
{OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."},
|
||||
{OPT_FSTR, "I", 0, "Ignored. (Placeholder for '-I' compiler options.)"},
|
||||
@@ -2482,6 +2501,9 @@
|
||||
if( strcmp(x,"name")==0 ){
|
||||
psp->declargslot = &(psp->gp->name);
|
||||
psp->insertLineMacro = 0;
|
||||
+ }else if( strcmp(x,"namespace")==0 ){
|
||||
+ psp->declargslot = &(psp->gp->namesp);
|
||||
+ psp->insertLineMacro = 0;
|
||||
}else if( strcmp(x,"include")==0 ){
|
||||
psp->declargslot = &(psp->gp->include);
|
||||
}else if( strcmp(x,"code")==0 ){
|
||||
@@ -3467,20 +3489,83 @@
|
||||
#define LINESIZE 1000
|
||||
/* The next cluster of routines are for reading the template file
|
||||
** and writing the results to the generated parser */
|
||||
+
|
||||
+/* Helper function to emit begin of namespace when namesp!=0
|
||||
+** Converts "ns1::ns2" to "namespace ns1 { namespace ns2 {"
|
||||
+*/
|
||||
+PRIVATE void tplt_namespace_begin(char *namesp, FILE *out)
|
||||
+{
|
||||
+ if(!namesp) return;
|
||||
+ while (ISSPACE(*namesp)) ++namesp;
|
||||
+
|
||||
+ char *cp = namesp;
|
||||
+ do {
|
||||
+ fprintf(out,"namespace ");
|
||||
+ cp = strchr(namesp, ':');
|
||||
+ if (cp) {
|
||||
+ while (namesp != cp) {
|
||||
+ fputc(*namesp,out);
|
||||
+ ++namesp;
|
||||
+ }
|
||||
+ while(*namesp == ':') ++namesp;
|
||||
+ }
|
||||
+ else {
|
||||
+ while (*namesp && !ISSPACE(*namesp)) {
|
||||
+ fputc(*namesp,out);
|
||||
+ ++namesp;
|
||||
+ }
|
||||
+ }
|
||||
+ fprintf(out, " {");
|
||||
+ } while (cp);
|
||||
+ fputc('\n',out);
|
||||
+}
|
||||
+
|
||||
+/* Helper function to emit end of namespace when namesp!=0
|
||||
+** Converts "ns1::ns2" to "}} // End namespace"
|
||||
+*/
|
||||
+PRIVATE void tplt_namespace_end(char *namesp, FILE *out)
|
||||
+{
|
||||
+ if(!namesp) return;
|
||||
+ while (ISSPACE(*namesp)) ++namesp;
|
||||
+
|
||||
+ char *cp = namesp;
|
||||
+ do {
|
||||
+ cp = strchr(cp, ':');
|
||||
+ if (cp) {
|
||||
+ while(*cp == ':') ++cp;
|
||||
+ }
|
||||
+ fputc('}',out);
|
||||
+ } while (cp);
|
||||
+
|
||||
+ fprintf(out," // End namespace %s\n", namesp);
|
||||
+}
|
||||
+
|
||||
/* The first function transfers data from "in" to "out" until
|
||||
** a line is seen which begins with "%%". The line number is
|
||||
** tracked.
|
||||
**
|
||||
** if name!=0, then any word that begin with "Parse" is changed to
|
||||
** begin with *name instead.
|
||||
+**
|
||||
+** if namesp!=0, then replace %namespace_begin / %namespace_end
|
||||
*/
|
||||
-PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno)
|
||||
+PRIVATE void tplt_xfer(char *name, char *namesp, FILE *in, FILE *out, int *lineno)
|
||||
{
|
||||
int i, iStart;
|
||||
char line[LINESIZE];
|
||||
while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){
|
||||
(*lineno)++;
|
||||
iStart = 0;
|
||||
+ if(line[0]=='%' && line[1]=='n'){
|
||||
+ if(strncmp(&line[1],"namespace_begin",15)==0){
|
||||
+ tplt_namespace_begin(namesp, out);
|
||||
+ continue;
|
||||
+ }else if(strncmp(&line[1],"namespace_end",13)==0){
|
||||
+ tplt_namespace_end(namesp, out);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if( name ){
|
||||
for(i=0; line[i]; i++){
|
||||
if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0
|
||||
@@ -4175,13 +4260,14 @@
|
||||
|
||||
in = tplt_open(lemp);
|
||||
if( in==0 ) return;
|
||||
- out = file_open(lemp,".c","wb");
|
||||
+ if(code_ext) out = file_open(lemp,code_ext,"wb");
|
||||
+ else out = file_open(lemp,".c","wb");
|
||||
if( out==0 ){
|
||||
fclose(in);
|
||||
return;
|
||||
}
|
||||
lineno = 1;
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate the include code, if any */
|
||||
tplt_print(out,lemp,lemp->include,&lineno);
|
||||
@@ -4190,7 +4276,7 @@
|
||||
fprintf(out,"#include \"%s\"\n", incName); lineno++;
|
||||
free(incName);
|
||||
}
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate #defines for all tokens */
|
||||
if( mhflag ){
|
||||
@@ -4204,7 +4290,7 @@
|
||||
}
|
||||
fprintf(out,"#endif\n"); lineno++;
|
||||
}
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate the defines */
|
||||
fprintf(out,"#define YYCODETYPE %s\n",
|
||||
@@ -4367,7 +4453,7 @@
|
||||
fprintf(out,"#define YY_MIN_REDUCE %d\n", lemp->minReduce); lineno++;
|
||||
i = lemp->minReduce + lemp->nrule;
|
||||
fprintf(out,"#define YY_MAX_REDUCE %d\n", i-1); lineno++;
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Now output the action table and its associates:
|
||||
**
|
||||
@@ -4489,7 +4575,7 @@
|
||||
}
|
||||
}
|
||||
fprintf(out, "};\n"); lineno++;
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate the table of fallback tokens.
|
||||
*/
|
||||
@@ -4508,7 +4594,7 @@
|
||||
lineno++;
|
||||
}
|
||||
}
|
||||
- tplt_xfer(lemp->name, in, out, &lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp, in, out, &lineno);
|
||||
|
||||
/* Generate a table containing the symbolic name of every symbol
|
||||
*/
|
||||
@@ -4516,7 +4602,7 @@
|
||||
lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name);
|
||||
fprintf(out," /* %4d */ \"%s\",\n",i, lemp->symbols[i]->name); lineno++;
|
||||
}
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate a table containing a text string that describes every
|
||||
** rule in the rule set of the grammar. This information is used
|
||||
@@ -4528,7 +4614,7 @@
|
||||
writeRuleText(out, rp);
|
||||
fprintf(out,"\",\n"); lineno++;
|
||||
}
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate code which executes every time a symbol is popped from
|
||||
** the stack while processing errors or while destroying the parser.
|
||||
@@ -4591,11 +4677,11 @@
|
||||
emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
|
||||
fprintf(out," break;\n"); lineno++;
|
||||
}
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate code which executes whenever the parser stack overflows */
|
||||
tplt_print(out,lemp,lemp->overflow,&lineno);
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate the tables of rule information. yyRuleInfoLhs[] and
|
||||
** yyRuleInfoNRhs[].
|
||||
@@ -4608,13 +4694,13 @@
|
||||
rule_print(out, rp);
|
||||
fprintf(out," */\n"); lineno++;
|
||||
}
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
|
||||
fprintf(out," %3d, /* (%d) ", -rp->nrhs, i);
|
||||
rule_print(out, rp);
|
||||
fprintf(out," */\n"); lineno++;
|
||||
}
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate code which execution during each REDUCE action */
|
||||
i = 0;
|
||||
@@ -4664,19 +4750,19 @@
|
||||
}
|
||||
}
|
||||
fprintf(out," break;\n"); lineno++;
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate code which executes if a parse fails */
|
||||
tplt_print(out,lemp,lemp->failure,&lineno);
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate code which executes when a syntax error occurs */
|
||||
tplt_print(out,lemp,lemp->error,&lineno);
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Generate code which executes when the parser accepts its input */
|
||||
tplt_print(out,lemp,lemp->accept,&lineno);
|
||||
- tplt_xfer(lemp->name,in,out,&lineno);
|
||||
+ tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno);
|
||||
|
||||
/* Append any addition code the user desires */
|
||||
tplt_print(out,lemp,lemp->extracode,&lineno);
|
Loading…
Reference in New Issue
Block a user