From a718d4a899f01cc95da02aaf1f75368fbcd53bfb Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:16:20 +0200 Subject: [PATCH 01/12] Make git ignore object and executable files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 43db904..e6d383c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +*.o +lemon +lemon.exe + # Xcode # build/ From 3e88f5e9943728f65909467019d3feec11a7c824 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:17:36 +0200 Subject: [PATCH 02/12] Rename variable xp => lemp for consistency --- src/build.c | 10 +++++----- src/build.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/build.c b/src/build.c index b35d381..beb1746 100644 --- a/src/build.c +++ b/src/build.c @@ -17,10 +17,10 @@ #include "struct.h" #include "table.h" -void FindRulePrecedences(struct lemon *xp) +void FindRulePrecedences(struct lemon *lemp) { struct rule *rp; - for(rp=xp->rule; rp; rp=rp->next){ + for(rp=lemp->rule; rp; rp=rp->next){ if( rp->precsym==0 ){ int i, j; for(i=0; inrhs && rp->precsym==0; i++){ @@ -46,14 +46,14 @@ void FindFirstSets(struct lemon *lemp) int i, j; struct rule *rp; int progress; - + for(i=0; insymbol; i++){ lemp->symbols[i]->lambda = LEMON_FALSE; } for(i=lemp->nterminal; insymbol; i++){ lemp->symbols[i]->firstset = SetNew(); } - + /* First compute all lambdas */ do{ progress = 0; @@ -69,7 +69,7 @@ void FindFirstSets(struct lemon *lemp) } } }while( progress ); - + /* Now compute all first sets */ do{ struct symbol *s1, *s2; diff --git a/src/build.h b/src/build.h index 339a9d5..0c96fd5 100644 --- a/src/build.h +++ b/src/build.h @@ -29,9 +29,9 @@ * are not RHS symbols with a defined precedence, the precedence * symbol field is left blank. */ -void FindRulePrecedences(struct lemon *xp); +void FindRulePrecedences(struct lemon *lemp); -/** +/** * Find all nonterminals which will generate the empty string. * Then go back and compute the first sets of every nonterminal. * The first set is the set of all terminal symbols which can begin @@ -39,7 +39,7 @@ void FindRulePrecedences(struct lemon *xp); */ void FindFirstSets(struct lemon *lemp); -/** +/** * Compute all LR(0) states for the grammar. Links * are added to between some states so that the LR(1) follow sets * can be computed later. @@ -51,7 +51,7 @@ void FindStates(struct lemon *lemp); */ void FindLinks(struct lemon *lemp); -/** +/** * Compute all followsets. * * A followset is the set of all symbols which can come immediately From 6bed50f4b3ca87b1117eb4003aa585c5119786b3 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:21:27 +0200 Subject: [PATCH 03/12] Make sure all forward decls use prototypes --- src/build.c | 47 +++++++++++++++++++++++++---------------------- src/table.h | 4 ++-- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/build.c b/src/build.c index beb1746..0a49da6 100644 --- a/src/build.c +++ b/src/build.c @@ -98,15 +98,15 @@ void FindFirstSets(struct lemon *lemp) return; } -PRIVATE struct state *getstate(/* struct lemon * */); /* forward reference */ +PRIVATE struct state *getstate(struct lemon *lemp); /* forward reference */ void FindStates(struct lemon *lemp) { struct symbol *sp; struct rule *rp; - + Configlist_init(); - + /* Find the start symbol */ if( lemp->start ){ sp = Symbol_find(lemp->start); @@ -121,7 +121,7 @@ void FindStates(struct lemon *lemp) }else{ sp = lemp->rule->lhs; } - + /* Make sure the start symbol doesn't occur on the right-hand side of ** any rule. Report an error if it does. (YACC would generate a new ** start symbol in this case.) */ @@ -137,7 +137,7 @@ void FindStates(struct lemon *lemp) } } } - + /* The basis configuration set for the first state ** is all rules which have the start symbol as their ** left-hand side */ @@ -147,7 +147,7 @@ void FindStates(struct lemon *lemp) newcfp = Configlist_addbasis(rp,0); SetAdd(newcfp->fws,0); } - + /* Compute the first state. All other states will be ** computed automatically during the computation of the first one. ** The returned pointer to the first state is not used. */ @@ -163,12 +163,12 @@ PRIVATE struct state *getstate(struct lemon *lemp) { struct config *cfp, *bp; struct state *stp; - + /* Extract the sorted basis of the new state. The basis was constructed ** by prior calls to "Configlist_addbasis()". */ Configlist_sortbasis(); bp = Configlist_basis(); - + /* Get a state with the same basis */ stp = State_find(bp); if( stp ){ @@ -231,18 +231,18 @@ struct state *stp; /* The state from which successors are computed */ struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ struct state *newstp; /* A pointer to a successor state */ - + /* Each configuration becomes complete after it contibutes to a successor ** state. Initially, all configurations are incomplete */ for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE; - + /* Loop through all configurations of the state "stp" */ for(cfp=stp->cfp; cfp; cfp=cfp->next){ if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */ if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */ Configlist_reset(); /* Reset the new config set */ sp = cfp->rp->rhs[cfp->dot]; /* Symbol after the dot */ - + /* For every configuration in the state "stp" which has the symbol "sp" ** following its dot, add the same configuration to the basis set under ** construction but with the dot shifted one symbol to the right. */ @@ -255,11 +255,11 @@ struct state *stp; /* The state from which successors are computed */ new = Configlist_addbasis(bcfp->rp,bcfp->dot+1); Plink_add(&new->bplp,bcfp); } - + /* Get a pointer to the state described by the basis configuration set ** constructed in the preceding loop */ newstp = getstate(lemp); - + /* The state "newstp" is reached from the state "stp" by a shift action ** on the symbol "sp" */ if( sp->type==MULTITERMINAL ){ @@ -279,7 +279,7 @@ void FindLinks(struct lemon *lemp) struct config *cfp, *other; struct state *stp; struct plink *plp; - + /* Housekeeping detail: ** Add to every propagate link a pointer back to the state to ** which the link is attached. */ @@ -289,7 +289,7 @@ void FindLinks(struct lemon *lemp) cfp->stp = stp; } } - + /* Convert all backlinks into forward links. Only the forward ** links are used in the follow-set computation. */ for(i=0; instate; i++){ @@ -310,13 +310,13 @@ void FindFollowSets(struct lemon *lemp) struct plink *plp; int progress; int change; - + for(i=0; instate; i++){ for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ cfp->status = INCOMPLETE; } } - + do{ progress = 0; for(i=0; instate; i++){ @@ -335,7 +335,10 @@ void FindFollowSets(struct lemon *lemp) }while( progress ); } -static int resolve_conflict(); +static int resolve_conflict( + struct action *apx, + struct action *apy, + struct symbol *errsym); /* forward reference */ void FindActions(struct lemon *lemp) { @@ -344,7 +347,7 @@ void FindActions(struct lemon *lemp) struct state *stp; struct symbol *sp; struct rule *rp; - + /* Add all of the reduce actions ** A reduce action is added for each element of the followset of ** a configuration which has its dot at the extreme right. @@ -363,7 +366,7 @@ void FindActions(struct lemon *lemp) } } } - + /* Add the accepting token */ if( lemp->start ){ sp = Symbol_find(lemp->start); @@ -375,7 +378,7 @@ void FindActions(struct lemon *lemp) ** finite state machine) an action to ACCEPT if the lookahead is the ** start nonterminal. */ Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0); - + /* Resolve conflicts */ for(i=0; instate; i++){ struct action *ap, *nap; @@ -391,7 +394,7 @@ void FindActions(struct lemon *lemp) } } } - + /* Report an error for each rule that can never be reduced. */ for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = LEMON_FALSE; for(i=0; instate; i++){ diff --git a/src/table.h b/src/table.h index 07424b1..5b810b1 100644 --- a/src/table.h +++ b/src/table.h @@ -28,7 +28,7 @@ /* Routines for handling a strings */ -char *Strsafe(); +char *Strsafe(char *y); void Strsafe_init(void); int Strsafe_insert(char *); @@ -36,7 +36,7 @@ char *Strsafe_find(char *); /* Routines for handling symbols of the grammar */ -struct symbol *Symbol_new(); +struct symbol *Symbol_new(char *x); int Symbolcmpp(struct symbol **, struct symbol **); void Symbol_init(void); int Symbol_insert(struct symbol *, char *); From eaabc97dc7df04de6be454822e8ab83b71ebd067 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:24:29 +0200 Subject: [PATCH 04/12] Make sure all function definitions use prototypes --- src/build.c | 18 ++++---- src/configlist.c | 32 +++++++------- src/main.c | 38 ++++++++-------- src/msort.c | 2 +- src/option.c | 4 +- src/parse.c | 8 ++-- src/plink.c | 6 +-- src/report.c | 110 +++++++++++++++++++++++------------------------ src/set.c | 2 +- src/table.c | 36 ++++++++-------- 10 files changed, 126 insertions(+), 130 deletions(-) diff --git a/src/build.c b/src/build.c index 0a49da6..95561e6 100644 --- a/src/build.c +++ b/src/build.c @@ -203,9 +203,7 @@ PRIVATE struct state *getstate(struct lemon *lemp) /* ** Return true if two symbols are the same. */ -int same_symbol(a,b) -struct symbol *a; -struct symbol *b; +int same_symbol(struct symbol *a, struct symbol *b) { int i; if( a==b ) return 1; @@ -221,9 +219,9 @@ struct symbol *b; /* Construct all successor states to the given state. A "successor" ** state is any state which can be reached by a shift action. */ -PRIVATE void buildshifts(lemp,stp) -struct lemon *lemp; -struct state *stp; /* The state from which successors are computed */ +PRIVATE void buildshifts( + struct lemon *lemp, + struct state *stp) /* The state from which successors are computed */ { struct config *cfp; /* For looping thru the config closure of "stp" */ struct config *bcfp; /* For the inner loop on config closure of "stp" */ @@ -423,10 +421,10 @@ void FindActions(struct lemon *lemp) ** If either action is a SHIFT, then it must be apx. This ** function won't work if apx->type==REDUCE and apy->type==SHIFT. */ -static int resolve_conflict(apx,apy,errsym) -struct action *apx; -struct action *apy; -struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */ +static int resolve_conflict( + struct action *apx, + struct action *apy, + struct symbol *errsym) /* The error symbol (NULL otherwise) */ { struct symbol *spx, *spy; int errcnt = 0; diff --git a/src/configlist.c b/src/configlist.c index 75bcba2..0e67f33 100644 --- a/src/configlist.c +++ b/src/configlist.c @@ -27,7 +27,7 @@ static struct config *basis = 0; /* Top of list of basis configs */ static struct config **basisend = 0; /* End of list of basis configs */ /* Return a pointer to a new configuration */ -PRIVATE struct config *newconfig(){ +PRIVATE struct config *newconfig(void){ struct config *new; if( freelist==0 ){ int i; @@ -46,15 +46,14 @@ PRIVATE struct config *newconfig(){ } /* The configuration "old" is no longer used */ -PRIVATE void deleteconfig(old) -struct config *old; +PRIVATE void deleteconfig(struct config *old) { old->next = freelist; freelist = old; } /* Initialized the configuration list builder */ -void Configlist_init(){ +void Configlist_init(void){ current = 0; currentend = ¤t; basis = 0; @@ -64,7 +63,7 @@ void Configlist_init(){ } /* Initialized the configuration list builder */ -void Configlist_reset(){ +void Configlist_reset(void){ current = 0; currentend = ¤t; basis = 0; @@ -74,12 +73,12 @@ void Configlist_reset(){ } /* Add another configuration to the configuration list */ -struct config *Configlist_add(rp,dot) -struct rule *rp; /* The rule */ -int dot; /* Index into the RHS of the rule where the dot goes */ +struct config *Configlist_add( + struct rule *rp, /* The rule */ + int dot) /* Index into the RHS of the rule where the dot goes */ { struct config *cfp, model; - + assert( currentend!=0 ); model.rp = rp; model.dot = dot; @@ -104,7 +103,7 @@ int dot; /* Index into the RHS of the rule where the dot goes */ struct config *Configlist_addbasis(struct rule *rp, int dot) { struct config *cfp, model; - + assert( basisend!=0 ); assert( currentend!=0 ); model.rp = rp; @@ -135,7 +134,7 @@ void Configlist_closure(struct lemon *lemp) struct rule *rp, *newrp; struct symbol *sp, *xsp; int i, dot; - + assert( currentend!=0 ); for(cfp=current; cfp; cfp=cfp->next){ rp = cfp->rp; @@ -174,14 +173,14 @@ void Configlist_closure(struct lemon *lemp) } /* Sort the configuration list */ -void Configlist_sort(){ +void Configlist_sort(void){ current = (struct config *)msort((char *)current,(char **)&(current->next),(msort_comparator)Configcmp); currentend = 0; return; } /* Sort the basis configuration list */ -void Configlist_sortbasis(){ +void Configlist_sortbasis(void){ basis = (struct config *)msort((char *)current,(char **)&(current->bp),(msort_comparator)Configcmp); basisend = 0; return; @@ -189,7 +188,7 @@ void Configlist_sortbasis(){ /* Return a pointer to the head of the configuration list and ** reset the list */ -struct config *Configlist_return(){ +struct config *Configlist_return(void){ struct config *old; old = current; current = 0; @@ -199,7 +198,7 @@ struct config *Configlist_return(){ /* Return a pointer to the head of the configuration list and ** reset the list */ -struct config *Configlist_basis(){ +struct config *Configlist_basis(void){ struct config *old; old = basis; basis = 0; @@ -208,8 +207,7 @@ struct config *Configlist_basis(){ } /* Free all elements of the given configuration list */ -void Configlist_eat(cfp) -struct config *cfp; +void Configlist_eat(struct config *cfp) { struct config *nextcfp; for(; cfp; cfp=nextcfp){ diff --git a/src/main.c b/src/main.c index d2882fc..09dbecc 100644 --- a/src/main.c +++ b/src/main.c @@ -25,7 +25,7 @@ /* Report an out-of-memory condition and abort. This function ** is used mostly by the "MemoryCheck" macro in struct.h */ -void memory_error(){ +void memory_error(void){ ErrorMsg("lemon", LINENO_NONE, "Out of memory. Aborting...\n"); exit(1); } @@ -60,10 +60,10 @@ static void handle_D_option(char *z){ static void handle_l_option(char *z){ if (strcmp (z, "c") == 0) { language = LANG_C; - + } else if (strcmp (z, "c++") == 0) { language = LANG_CPP; - + } else if (strcmp (z, "d") == 0) { language = LANG_D; } @@ -95,7 +95,7 @@ int main(int argc, char **argv) }; int i; struct lemon lem; - + OptInit(argv,options,stderr); if( version ){ printf("Lemon version 1.0\n"); @@ -107,7 +107,7 @@ int main(int argc, char **argv) } memset(&lem, 0, sizeof(lem)); lem.errorcnt = 0; - + /* Initialize the machine */ Strsafe_init(); Symbol_init(); @@ -118,7 +118,7 @@ int main(int argc, char **argv) Symbol_new("$"); lem.errsym = Symbol_new("error"); lem.errsym->useCnt = 0; - + /* Parse the input file */ Parse(&lem); if( lem.errorcnt ) exit(lem.errorcnt); @@ -126,7 +126,7 @@ int main(int argc, char **argv) ErrorMsg(lem.filename, LINENO_NONE, "Empty grammar.\n"); exit(1); } - + /* Count and index the symbols of the grammar */ lem.nsymbol = Symbol_count(); Symbol_new("{default}"); @@ -137,49 +137,49 @@ int main(int argc, char **argv) for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; for(i=1; isupper(lem.symbols[i]->name[0]); i++); lem.nterminal = i; - + /* Generate a reprint of the grammar, if requested on the command line */ if( rpflag ){ Reprint(&lem); }else{ /* Initialize the size for all follow and first sets */ SetSize(lem.nterminal+1); - + /* Find the precedence for every production rule (that has one) */ FindRulePrecedences(&lem); - + /* Compute the lambda-nonterminals and the first-sets for every ** nonterminal */ FindFirstSets(&lem); - + /* Compute all LR(0) states. Also record follow-set propagation ** links so that the follow-set can be computed later */ lem.nstate = 0; FindStates(&lem); lem.sorted = State_arrayof(); - + /* Tie up loose ends on the propagation links */ FindLinks(&lem); - + /* Compute the follow set of every reducible configuration */ FindFollowSets(&lem); - + /* Compute the action tables */ FindActions(&lem); - + /* Compress the action tables */ if( compress==0 ) CompressTables(&lem); - + /* Reorder and renumber the states so that states with fewer choices ** occur at the end. */ ResortStates(&lem); - + /* Generate a report of the parser generated. (the "y.output" file) */ if( !quiet ) ReportOutput(&lem); - + /* Generate the source code for the parser */ ReportTable(&lem, mhflag); - + /* Produce a header file for use by the scanner. (This step is ** omitted if the "-m" option is used because makeheaders will ** generate the file for us.) */ diff --git a/src/msort.c b/src/msort.c index 13599cc..a1ae73c 100644 --- a/src/msort.c +++ b/src/msort.c @@ -54,7 +54,7 @@ */ static char *merge(char *a, char *b, msort_comparator cmp, ptrdiff_t offset){ char *ptr, *head; - + if( a==0 ){ head = b; }else if( b==0 ){ diff --git a/src/option.c b/src/option.c index 154aa9a..433b8a4 100644 --- a/src/option.c +++ b/src/option.c @@ -206,7 +206,7 @@ int OptInit(char **a, struct s_options *o, FILE *err) return 0; } -int OptNArgs(){ +int OptNArgs(void){ int cnt = 0; int dashdash = 0; int i; @@ -233,7 +233,7 @@ void OptErr(int n) if( i>=0 ) errline(i,0,errstream); } -void OptPrint(){ +void OptPrint(void){ int i; int max, len; max = 0; diff --git a/src/parse.c b/src/parse.c index 9fda715..f3254d8 100644 --- a/src/parse.c +++ b/src/parse.c @@ -541,13 +541,13 @@ void Parse(struct lemon *gp) int c; char *cp, *nextcp; int startline = 0; - + memset(&ps, '\0', sizeof(ps)); ps.gp = gp; ps.filename = gp->filename; ps.errorcnt = 0; ps.state = INITIALIZE; - + /* Begin by reading the input file */ fp = fopen(ps.filename,"rb"); if( fp==0 ){ @@ -574,10 +574,10 @@ void Parse(struct lemon *gp) } fclose(fp); filebuf[filesize] = 0; - + /* Make an initial pass through the file to handle %ifdef and %ifndef */ preprocess_input(filebuf); - + /* Now scan the text of the input file */ lineno = 1; for(cp=filebuf; (c= *cp)!=0; ){ diff --git a/src/plink.c b/src/plink.c index eb9a397..a0e8f9a 100644 --- a/src/plink.c +++ b/src/plink.c @@ -18,9 +18,9 @@ static struct plink *plink_freelist = 0; /* Allocate a new plink */ -struct plink *Plink_new(){ +struct plink *Plink_new(void){ struct plink *new; - + if( plink_freelist==0 ){ int i; int amt = 100; @@ -63,7 +63,7 @@ void Plink_copy(struct plink **to, struct plink *from) void Plink_delete(struct plink *plp) { struct plink *nextpl; - + while( plp ){ nextpl = plp->next; plp->next = plink_freelist; diff --git a/src/report.c b/src/report.c index 78f7be0..4938ce0 100644 --- a/src/report.c +++ b/src/report.c @@ -26,7 +26,7 @@ PRIVATE char *file_makename(struct lemon *lemp, char *suffix) { char *name; char *cp; - + name = malloc( strlen(lemp->filename) + strlen(suffix) + 5 ); if( name==0 ){ ErrorMsg("lemon", LINENO_NONE, "Can't allocate space for a filename.\n"); @@ -45,7 +45,7 @@ PRIVATE char *file_makename(struct lemon *lemp, char *suffix) PRIVATE FILE *file_open(struct lemon *lemp, char *suffix, char *mode) { FILE *fp; - + if( lemp->outname ) free(lemp->outname); lemp->outname = file_makename(lemp, suffix); fp = fopen(lemp->outname,mode); @@ -198,7 +198,7 @@ void ReportOutput(struct lemon *lemp) struct config *cfp; struct action *ap; FILE *fp; - + fp = file_open(lemp,".out","wb"); if( fp==0 ) return; for(i=0; instate; i++){ @@ -235,7 +235,7 @@ void ReportOutput(struct lemon *lemp) for(i=0; insymbol; i++){ int j; struct symbol *sp; - + sp = lemp->symbols[i]; fprintf(fp, " %3d: %s", i, sp->name); if( sp->type==NONTERMINAL ){ @@ -262,7 +262,7 @@ PRIVATE char *pathsearch(char *argv0, char *name, int modemask) char *pathlist; char *path,*cp; char c; - + #ifdef __WIN32__ cp = strrchr(argv0,'\\'); #else @@ -358,7 +358,7 @@ PRIVATE FILE *tplt_open(struct lemon *lemp) FILE *in; char *tpltname; char *cp; - + cp = strrchr(lemp->filename,'.'); if( cp ){ sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename); @@ -432,7 +432,7 @@ PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int strln, int void emit_destructor_code(FILE *out, struct symbol *sp, struct lemon *lemp, int *lineno) { char *cp = 0; - + int linecnt = 0; if( sp->type==TERMINAL ){ cp = lemp->tokendest; @@ -498,7 +498,7 @@ PRIVATE char *append_str(char *zText, int n, int p1, int p2){ static int used = 0; int c; char zInt[40]; - + if( zText==0 ){ used = 0; return z; @@ -542,15 +542,15 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ int i; char lhsused = 0; /* True if the LHS element has been used */ char used[MAXRHS]; /* True for each RHS element which is used */ - + for(i=0; inrhs; i++) used[i] = 0; lhsused = 0; - + if( rp->code==0 ){ rp->code = "\n"; rp->line = rp->ruleline; } - + append_str(0,0,0,0); for(cp=rp->code; *cp; cp++){ if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){ @@ -589,7 +589,7 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ } append_str(cp, 1, 0, 0); } /* End loop */ - + /* Check to make sure the LHS has been used */ if( rp->lhsalias && !lhsused ){ ErrorMsg(lemp->filename,rp->ruleline, @@ -597,7 +597,7 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ rp->lhsalias,rp->lhs->name,rp->lhsalias); lemp->errorcnt++; } - + /* Generate destructor code for RHS symbols which are not used in the ** reduce code */ for(i=0; inrhs; i++){ @@ -629,7 +629,7 @@ PRIVATE void emit_code(FILE *out, struct rule *rp, struct lemon *lemp, int *line { char *cp; int linecnt = 0; - + /* Generate code to do the reduce action */ if( rp->code ){ tplt_linedir(out,rp->line,lemp->filename); @@ -641,7 +641,7 @@ PRIVATE void emit_code(FILE *out, struct rule *rp, struct lemon *lemp, int *line fprintf(out,"}\n"); tplt_linedir(out,*lineno,lemp->outname); } /* End if( rp->code ) */ - + return; } @@ -666,7 +666,7 @@ void print_stack_union( int i,j; /* Loop counters */ int hash; /* For hashing the name of a type */ char *name; /* Name of the parser */ - + /* Allocate and initialize types[] and allocate stddt[] */ arraysize = lemp->nsymbol * 2; types = (char**)calloc( arraysize, sizeof(char*) ); @@ -687,7 +687,7 @@ void print_stack_union( ErrorMsg("lemon", LINENO_NONE, "Out of memory.\n"); exit(1); } - + /* Build a hash table of datatypes. The ".dtnum" field of each symbol ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is ** used for terminal symbols. If there is no %default_type defined then @@ -735,14 +735,14 @@ void print_stack_union( strcpy(types[hash],stddt); } } - + /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */ lineno = *plineno; if (language == LANG_D) { /* D language. */ fprintf(out,"alias %s token_t;\n", lemp->tokentype ? lemp->tokentype : "void*"); lineno++; - + fprintf(out,"private union YYMINORTYPE {\n"); lineno++; fprintf(out," token_t yy0;\n"); lineno++; for(i=0; iname ? lemp->name : "Parse"; @@ -860,7 +860,7 @@ void ReportTable( int mnTknOfst, mxTknOfst; int mnNtOfst, mxNtOfst; struct axset *ax; - + in = tplt_open(lemp); if( in==0 ) return; out = file_open(lemp, language==LANG_D ? ".d" : @@ -872,7 +872,7 @@ void ReportTable( } lineno = 1; tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate the include code, if any */ tplt_print(out,lemp,lemp->include,lemp->includeln,&lineno); if( mhflag ){ @@ -881,7 +881,7 @@ void ReportTable( free(name); } tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate #defines for all tokens */ if (language == LANG_D) { char *prefix = lemp->tokenprefix ? lemp->tokenprefix : ""; @@ -905,7 +905,7 @@ void ReportTable( fprintf(out,"#endif\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate the defines */ if (language == LANG_D) { /* D language. */ @@ -922,7 +922,7 @@ void ReportTable( fprintf(out,"const int YYNRULE = %d;\n",lemp->nrule); lineno++; fprintf(out,"const int YYERRORSYMBOL = %d;\n", lemp->errsym->useCnt ? lemp->errsym->index : -1); lineno++; - + } else { /* C and C++ languages. */ fprintf(out,"#define YYCODETYPE %s\n", @@ -977,7 +977,7 @@ void ReportTable( } } tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate the action table and its associates: ** ** yy_action[] A single table containing all actions. @@ -989,7 +989,7 @@ void ReportTable( ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ - + /* Compute the actions on all states and count them up */ ax = calloc(lemp->nstate*2, sizeof(ax[0])); if( ax==0 ){ @@ -1007,7 +1007,7 @@ void ReportTable( } mxTknOfst = mnTknOfst = 0; mxNtOfst = mnNtOfst = 0; - + /* Compute the action table. In order to try to keep the size of the ** action table to a minimum, the heuristic of placing the largest action ** sets first is used. @@ -1042,7 +1042,7 @@ void ReportTable( } } free(ax); - + /* Output the yy_action table */ if (language == LANG_D) fprintf(out,"private static const YYACTIONTYPE yy_action[] = [\n"); @@ -1067,7 +1067,7 @@ void ReportTable( else fprintf(out, "};\n"); lineno++; - + /* Output the yy_lookahead table */ if (language == LANG_D) fprintf(out,"private static const YYCODETYPE yy_lookahead[] = [\n"); @@ -1091,7 +1091,7 @@ void ReportTable( else fprintf(out, "};\n"); lineno++; - + /* Output the yy_shift_ofst[] table */ if (language == LANG_D) fprintf(out, "const int YY_SHIFT_USE_DFLT = %d;\n", mnTknOfst-1); @@ -1131,7 +1131,7 @@ void ReportTable( else fprintf(out, "};\n"); lineno++; - + /* Output the yy_reduce_ofst[] table */ if (language == LANG_D) fprintf(out, "const int YY_REDUCE_USE_DFLT = %d;\n", mnNtOfst-1); @@ -1171,7 +1171,7 @@ void ReportTable( else fprintf(out, "};\n"); lineno++; - + /* Output the default action table */ if (language == LANG_D) fprintf(out, "private static const YYACTIONTYPE yy_default[] = [\n"); @@ -1196,7 +1196,7 @@ void ReportTable( fprintf(out, "};\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate the table of fallback tokens. */ if( lemp->has_fallback ){ @@ -1212,7 +1212,7 @@ void ReportTable( } } tplt_xfer(lemp->name, in, out, &lineno); - + /* Generate a table containing the symbolic name of every symbol */ for(i=0; insymbol; i++){ @@ -1222,7 +1222,7 @@ void ReportTable( } if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate a table containing a text string that describes every ** rule in the rule set of the grammer. This information is used ** when tracing REDUCE actions. @@ -1234,7 +1234,7 @@ void ReportTable( fprintf(out,"\",\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate code which executes every time a symbol is popped from ** the stack while processing errors or while destroying the parser. ** (In other words, generate the %destructor actions) @@ -1272,7 +1272,7 @@ void ReportTable( if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; - + /* Combine duplicate destructors into a single case */ for(j=i+1; jnsymbol; j++){ struct symbol *sp2 = lemp->symbols[j]; @@ -1284,16 +1284,16 @@ void ReportTable( sp2->destructor = 0; } } - + emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); fprintf(out," break;\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate code which executes whenever the parser stack overflows */ tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno); tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate the table of rule information ** ** Note: This code depends on the fact that rules are number @@ -1303,7 +1303,7 @@ void ReportTable( fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate code which execution during each REDUCE action */ for(rp=lemp->rule; rp; rp=rp->next){ translate_code(lemp, rp); @@ -1326,22 +1326,22 @@ void ReportTable( fprintf(out," break;\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate code which executes if a parse fails */ tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno); tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate code which executes when a syntax error occurs */ tplt_print(out,lemp,lemp->error,lemp->errorln,&lineno); tplt_xfer(lemp->name,in,out,&lineno); - + /* Generate code which executes when the parser accepts its input */ tplt_print(out,lemp,lemp->accept,lemp->acceptln,&lineno); tplt_xfer(lemp->name,in,out,&lineno); - + /* Append any addition code the user desires */ tplt_print(out,lemp,lemp->extracode,lemp->extracodeln,&lineno); - + fclose(in); fclose(out); return; @@ -1355,7 +1355,7 @@ void ReportHeader(struct lemon *lemp) char line[LINESIZE]; char pattern[LINESIZE]; int i; - + if( lemp->tokenprefix ) prefix = lemp->tokenprefix; else prefix = ""; in = file_open(lemp,".h","rb"); @@ -1395,13 +1395,13 @@ void CompressTables(struct lemon *lemp) int nbest, n; int i; int usesWildcard; - + for(i=0; instate; i++){ stp = lemp->sorted[i]; nbest = 0; rbest = 0; usesWildcard = 0; - + for(ap=stp->ap; ap; ap=ap->next){ if( ap->type==SHIFT && ap->sp==lemp->wildcard ){ usesWildcard = 1; @@ -1422,14 +1422,14 @@ void CompressTables(struct lemon *lemp) rbest = rp; } } - + /* Do not make a default if the number of rules to default ** is not at least 1 or if the wildcard token is a possible ** lookahead. */ if( nbest<1 || usesWildcard ) continue; - - + + /* Combine matching REDUCE actions into a single default */ for(ap=stp->ap; ap; ap=ap->next){ if( ap->type==REDUCE && ap->x.rp==rbest ) break; @@ -1454,7 +1454,7 @@ static int stateResortCompare(const void *a, const void *b){ const struct state *pA = *(const struct state**)a; const struct state *pB = *(const struct state**)b; int n; - + n = pB->nNtAct - pA->nNtAct; if( n==0 ){ n = pB->nTknAct - pA->nTknAct; @@ -1472,7 +1472,7 @@ void ResortStates(struct lemon *lemp) int i; struct state *stp; struct action *ap; - + for(i=0; instate; i++){ stp = lemp->sorted[i]; stp->nTknAct = stp->nNtAct = 0; diff --git a/src/set.c b/src/set.c index 372b4f8..5e99379 100644 --- a/src/set.c +++ b/src/set.c @@ -22,7 +22,7 @@ void SetSize(int n) } /* Allocate a new set */ -char *SetNew(){ +char *SetNew(void){ char *s; s = (char*)calloc( size, 1); if( s==0 ){ diff --git a/src/table.c b/src/table.c index e93fc5b..73da15e 100644 --- a/src/table.c +++ b/src/table.c @@ -35,7 +35,7 @@ PRIVATE int strhash(char *x) char *Strsafe(char *y) { char *z; - + if( y==0 ) return 0; z = Strsafe_find(y); if( z==0 && (z=malloc( strlen(y)+1 ))!=0 ){ @@ -71,7 +71,7 @@ typedef struct s_x1node { static struct s_x1 *x1a; /* Allocate a new associative array */ -void Strsafe_init(){ +void Strsafe_init(void){ if( x1a ) return; x1a = (struct s_x1*)malloc( sizeof(struct s_x1) ); if( x1a ){ @@ -96,7 +96,7 @@ int Strsafe_insert(char *data) x1node *np; int h; int ph; - + if( x1a==0 ) return 0; ph = strhash(data); h = ph & (x1a->size-1); @@ -151,7 +151,7 @@ char *Strsafe_find(char *key) { int h; x1node *np; - + if( x1a==0 ) return 0; h = strhash(key) & (x1a->size-1); np = x1a->ht[h]; @@ -168,7 +168,7 @@ char *Strsafe_find(char *key) struct symbol *Symbol_new(char *x) { struct symbol *sp; - + sp = Symbol_find(x); if( sp==0 ){ sp = (struct symbol *)calloc(1, sizeof(struct symbol) ); @@ -232,7 +232,7 @@ typedef struct s_x2node { static struct s_x2 *x2a; /* Allocate a new associative array */ -void Symbol_init(){ +void Symbol_init(void){ if( x2a ) return; x2a = (struct s_x2*)malloc( sizeof(struct s_x2) ); if( x2a ){ @@ -257,7 +257,7 @@ int Symbol_insert(struct symbol *data, char *key) x2node *np; int h; int ph; - + if( x2a==0 ) return 0; ph = strhash(key); h = ph & (x2a->size-1); @@ -314,7 +314,7 @@ struct symbol *Symbol_find(char *key) { int h; x2node *np; - + if( x2a==0 ) return 0; h = strhash(key) & (x2a->size-1); np = x2a->ht[h]; @@ -338,7 +338,7 @@ struct symbol *Symbol_Nth(int n) } /* Return the size of the array */ -int Symbol_count() +int Symbol_count(void) { return x2a ? x2a->count : 0; } @@ -346,7 +346,7 @@ int Symbol_count() /* Return an array of pointers to all data in the table. ** The array is obtained from malloc. Return NULL if memory allocation ** problems, or if the array is empty. */ -struct symbol **Symbol_arrayof() +struct symbol **Symbol_arrayof(void) { struct symbol **array; int i,size; @@ -395,7 +395,7 @@ PRIVATE int statehash(struct config *a) } /* Allocate a new state structure */ -struct state *State_new() +struct state *State_new(void) { struct state *new; new = (struct state *)calloc(1, sizeof(struct state) ); @@ -429,7 +429,7 @@ typedef struct s_x3node { static struct s_x3 *x3a; /* Allocate a new associative array */ -void State_init(){ +void State_init(void){ if( x3a ) return; x3a = (struct s_x3*)malloc( sizeof(struct s_x3) ); if( x3a ){ @@ -454,7 +454,7 @@ int State_insert(struct state *data, struct config *key) x3node *np; int h; int ph; - + if( x3a==0 ) return 0; ph = statehash(key); h = ph & (x3a->size-1); @@ -511,7 +511,7 @@ struct state *State_find(struct config *key) { int h; x3node *np; - + if( x3a==0 ) return 0; h = statehash(key) & (x3a->size-1); np = x3a->ht[h]; @@ -525,7 +525,7 @@ struct state *State_find(struct config *key) /* Return an array of pointers to all data in the table. ** The array is obtained from malloc. Return NULL if memory allocation ** problems, or if the array is empty. */ -struct state **State_arrayof() +struct state **State_arrayof(void) { struct state **array; int i,size; @@ -571,7 +571,7 @@ typedef struct s_x4node { static struct s_x4 *x4a; /* Allocate a new associative array */ -void Configtable_init(){ +void Configtable_init(void){ if( x4a ) return; x4a = (struct s_x4*)malloc( sizeof(struct s_x4) ); if( x4a ){ @@ -596,7 +596,7 @@ int Configtable_insert(struct config *data) x4node *np; int h; int ph; - + if( x4a==0 ) return 0; ph = confighash(data); h = ph & (x4a->size-1); @@ -651,7 +651,7 @@ struct config *Configtable_find(struct config *key) { int h; x4node *np; - + if( x4a==0 ) return 0; h = confighash(key) & (x4a->size-1); np = x4a->ht[h]; From 747fb5cdb0c7fc9e1defea34150c1fb131ac7e48 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:24:50 +0200 Subject: [PATCH 05/12] Add and use an UNUSED_ARG macro --- src/build.c | 1 + src/error.h | 2 ++ src/main.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/build.c b/src/build.c index 95561e6..02b2484 100644 --- a/src/build.c +++ b/src/build.c @@ -426,6 +426,7 @@ static int resolve_conflict( struct action *apy, struct symbol *errsym) /* The error symbol (NULL otherwise) */ { + UNUSED_ARG(errsym); struct symbol *spx, *spy; int errcnt = 0; assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */ diff --git a/src/error.h b/src/error.h index ff3008d..6d7a29f 100644 --- a/src/error.h +++ b/src/error.h @@ -12,6 +12,8 @@ #include "lemon.h" +#define UNUSED_ARG(x) (void) x + enum { LINENO_NONE = 0 }; diff --git a/src/main.c b/src/main.c index 09dbecc..11b4b6f 100644 --- a/src/main.c +++ b/src/main.c @@ -73,6 +73,8 @@ static void handle_l_option(char *z){ /* The main program. Parse the command line and do it... */ int main(int argc, char **argv) { + UNUSED_ARG(argc); + static int version = 0; static int rpflag = 0; static int basisflag = 0; From fb9d74e0441384b38914eed157b58e90d326f1a5 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:25:07 +0200 Subject: [PATCH 06/12] Add missing include of stddef.h (for ptrdiff_t) --- src/msort.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/msort.c b/src/msort.c index a1ae73c..ad8779b 100644 --- a/src/msort.c +++ b/src/msort.c @@ -7,6 +7,7 @@ * See LICENSE for additional information. */ +#include #include "msort.h" /* From 878816ebca7620b46c3b1e1cebb00c5287a656c7 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:25:30 +0200 Subject: [PATCH 07/12] Declare some variables as size_t, which they are --- src/parse.c | 5 +++-- src/report.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/parse.c b/src/parse.c index f3254d8..f3e55aa 100644 --- a/src/parse.c +++ b/src/parse.c @@ -481,7 +481,8 @@ static void parseonetoken(struct pstate *psp) ** comments them out. Text in between is also commented out as appropriate. */ static void preprocess_input(char *z){ - int i, j, k, n; + int i, j, k; + size_t n; int exclude = 0; int start = 0; int lineno = 1; @@ -536,7 +537,7 @@ void Parse(struct lemon *gp) struct pstate ps; FILE *fp; char *filebuf; - int filesize; + size_t filesize; int lineno; int c; char *cp, *nextcp; diff --git a/src/report.c b/src/report.c index 4938ce0..6df55d8 100644 --- a/src/report.c +++ b/src/report.c @@ -494,7 +494,7 @@ int has_destructor(struct symbol *sp, struct lemon *lemp) */ PRIVATE char *append_str(char *zText, int n, int p1, int p2){ static char *z = 0; - static int alloced = 0; + static size_t alloced = 0; static int used = 0; int c; char zInt[40]; From ec445a3e85fb46bb976576a501b9c4cddab80df6 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:16:32 +0200 Subject: [PATCH 08/12] Add a simple Makefile Simple build rules; more importantly, makes sure everything builds with -Wall and -Wextra. --- src/Makefile | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/Makefile diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..9c25c03 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,32 @@ +all: lemon + +CFLAGS += -Wall +CFLAGS += -Wextra +# CFLAGS += -g +# CFLAGS += -O + +C_SRCS = \ + action.c \ + build.c \ + configlist.c \ + error.c \ + main.c \ + msort.c \ + option.c \ + parse.c \ + plink.c \ + report.c \ + set.c \ + table.c \ + +C_OBJS = $(C_SRCS:.c=.o) + +%.o: %.c + cc $(CFLAGS) -c -o $@ $^ + +lemon: $(C_OBJS) + cc -o $@ $^ + +clean: + rm -f $(C_OBJS) + rm -f lemon From f4f41fe814ae1e292822e0e455f4c55196cba238 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:56:55 +0200 Subject: [PATCH 09/12] Ignore vim .swp files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e6d383c..060f997 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.swp *.o lemon lemon.exe From 73a74f33785685fbf8a4ea210e4ce50495abc867 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 17:57:23 +0200 Subject: [PATCH 10/12] Add install target to Makefile --- src/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Makefile b/src/Makefile index 9c25c03..45ea9d2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -19,6 +19,10 @@ C_SRCS = \ set.c \ table.c \ +INSTALL_DIR = /usr/local +INSTALL_DIR_BIN = $(INSTALL_DIR)/bin +INSTALL_DIR_SHARE = $(INSTALL_DIR)/share/lemon + C_OBJS = $(C_SRCS:.c=.o) %.o: %.c @@ -27,6 +31,11 @@ C_OBJS = $(C_SRCS:.c=.o) lemon: $(C_OBJS) cc -o $@ $^ +install: lemon + mkdir -p $(INSTALL_DIR) $(INSTALL_DIR_BIN) $(INSTALL_DIR_SHARE) + cp lemon $(INSTALL_DIR_BIN) + cp ../templates/skeleton.c $(INSTALL_DIR_SHARE) + clean: rm -f $(C_OBJS) rm -f lemon From 66629f64cf070f93d3616eba681c36f946a5cd41 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 18:02:04 +0200 Subject: [PATCH 11/12] Fix typos in examples README --- examples/README | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/README b/examples/README index df11f34..4643267 100644 --- a/examples/README +++ b/examples/README @@ -9,7 +9,7 @@ http://sourceforge.net/project/filemodule_monitor.php?filemodule_id=124528 example1.y ~~~~~~~~~~ - This is a very simple calulator. To compile the + This is a very simple calculator. To compile the example do the following: $ make @@ -79,7 +79,7 @@ example2.y This structure supports both a value and a count. You could add many more values, and allocate memory - to z if you wanted. One, note, you cannot put in + to z if you wanted. One note, you cannot put in C++ strings or other STL containers directly into this structure; instead, you would need to have pointers to such structures. Note, if memory was allocated for z, you'd @@ -95,7 +95,7 @@ example3.y example4.y ~~~~~~~~~~ - This is the first example that ends the grammer with + This is the first example that ends the grammar with a newline. In the file example4.y take a look at the following: @@ -116,7 +116,7 @@ example4.y example5.y ~~~~~~~~~~ This example puts everything together with flex. But, - take a peek at how lexer.l is complied in the Makefile + take a peek at how lexer.l is compiled in the Makefile with "flex lexer.l" instead of "flex++ lexer.l". The main_part5 for this example is in C++, so it's necessary to add the extern "C" directives. True it could have been @@ -159,7 +159,7 @@ http://www.hwaci.com/sw/lemon/ (4) Home of sqlite http://www.sqlite.org/ -(5) Glossory of paser terms +(5) Glossary of parser terms http://www.parsifalsoft.com/gloss.html (6) Good introduction to parsers From 94a4298c6c79e77d5be8fe6124f936e85e8831e6 Mon Sep 17 00:00:00 2001 From: Gonzalo Diethelm Date: Tue, 30 Apr 2019 18:02:15 +0200 Subject: [PATCH 12/12] Add .gitignore and Makefile for examples --- examples/.gitignore | 4 ++++ examples/Makefile | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 examples/.gitignore create mode 100644 examples/Makefile diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..980da8b --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,4 @@ +ex[0-9] +example[0-9].[ch] +example[0-9].out +lexer.c diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..3d043e4 --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,36 @@ +all: examples + +EXES = \ + ex1 \ + ex2 \ + ex3 \ + ex4 \ + ex5 \ + +ex1: example1.y exp1.c + lemon example1.y + cc -o $@ exp1.c + +ex2: example2.y exp2.c + lemon example2.y + cc -o $@ exp2.c + +ex3: example3.y exp3.c + lemon example3.y + cc -o $@ exp3.c + +ex4: example4.y exp4.c + lemon example4.y + cc -o $@ exp4.c + +ex5: example5.y exp5.c lexer.l + lemon example5.y + flex -o lexer.c lexer.l + cc -o $@ exp5.c lexer.c + +examples: $(EXES) + +clean: + rm -f $(EXES) + rm -f example[0-9].{c,h,out} + rm -f lexer.c