Revision | 84945d6486e0b86808762635b18aad52798ebc37 (tree) |
---|---|
Time | 2019-11-25 05:54:18 |
Author | Joshua Surace <doomjoshuaboy@gmai...> |
Commiter | Joshua Surace |
Merged lemon tool to the latest .
@@ -6,9 +6,9 @@ | ||
6 | 6 | ** |
7 | 7 | ** The author of this program disclaims copyright. |
8 | 8 | ** |
9 | -** This file is based on version 1.43 of lemon.c from the SQLite | |
10 | -** source tree, with modifications to make it work nicer when run | |
11 | -** by Developer Studio. | |
9 | +** This file is based on version 1.69 of lemon.c from the SQLite | |
10 | +** CVS, with modifications to make it work nicer when run | |
11 | +** from Developer Studio. | |
12 | 12 | */ |
13 | 13 | #include <stdio.h> |
14 | 14 | #include <stdarg.h> |
@@ -17,6 +17,14 @@ | ||
17 | 17 | #include <stdlib.h> |
18 | 18 | #include <assert.h> |
19 | 19 | |
20 | +#define ISSPACE(X) isspace((unsigned char)(X)) | |
21 | +#define ISDIGIT(X) isdigit((unsigned char)(X)) | |
22 | +#define ISALNUM(X) isalnum((unsigned char)(X)) | |
23 | +#define ISALPHA(X) isalpha((unsigned char)(X)) | |
24 | +#define ISUPPER(X) isupper((unsigned char)(X)) | |
25 | +#define ISLOWER(X) islower((unsigned char)(X)) | |
26 | + | |
27 | + | |
20 | 28 | #ifndef __WIN32__ |
21 | 29 | # if defined(_WIN32) || defined(WIN32) |
22 | 30 | # define __WIN32__ |
@@ -24,7 +32,13 @@ | ||
24 | 32 | #endif |
25 | 33 | |
26 | 34 | #ifdef __WIN32__ |
27 | -extern int access(); | |
35 | +#ifdef __cplusplus | |
36 | +extern "C" { | |
37 | +#endif | |
38 | +extern int access(char *path, int mode); | |
39 | +#ifdef __cplusplus | |
40 | +} | |
41 | +#endif | |
28 | 42 | #else |
29 | 43 | #include <unistd.h> |
30 | 44 | #endif |
@@ -38,8 +52,21 @@ | ||
38 | 52 | #define MAXRHS 1000 |
39 | 53 | #endif |
40 | 54 | |
55 | +static int showPrecedenceConflict = 0; | |
41 | 56 | static void *msort(void *list, void *next, int (*cmp)()); |
42 | 57 | |
58 | +/* | |
59 | +** Compilers are getting increasingly pedantic about type conversions | |
60 | +** as C evolves ever closer to Ada.... To work around the latest problems | |
61 | +** we have to define the following variant of strlen(). | |
62 | +*/ | |
63 | +#define lemonStrlen(X) ((int)strlen(X)) | |
64 | + | |
65 | +/* a few forward declarations... */ | |
66 | +struct rule; | |
67 | +struct lemon; | |
68 | +struct action; | |
69 | + | |
43 | 70 | /******** From the file "action.h" *************************************/ |
44 | 71 | static struct action *Action_new(void); |
45 | 72 | static struct action *Action_sort(struct action *); |
@@ -53,59 +80,58 @@ | ||
53 | 80 | void FindActions(); |
54 | 81 | |
55 | 82 | /********* From the file "configlist.h" *********************************/ |
56 | -void Configlist_init(/* void */); | |
57 | -struct config *Configlist_add(/* struct rule *, int */); | |
58 | -struct config *Configlist_addbasis(/* struct rule *, int */); | |
59 | -void Configlist_closure(/* void */); | |
60 | -void Configlist_sort(/* void */); | |
61 | -void Configlist_sortbasis(/* void */); | |
62 | -struct config *Configlist_return(/* void */); | |
63 | -struct config *Configlist_basis(/* void */); | |
64 | -void Configlist_eat(/* struct config * */); | |
65 | -void Configlist_reset(/* void */); | |
83 | +void Configlist_init(void); | |
84 | +struct config *Configlist_add(struct rule *, int); | |
85 | +struct config *Configlist_addbasis(struct rule *, int); | |
86 | +void Configlist_closure(struct lemon *); | |
87 | +void Configlist_sort(void); | |
88 | +void Configlist_sortbasis(void); | |
89 | +struct config *Configlist_return(void); | |
90 | +struct config *Configlist_basis(void); | |
91 | +void Configlist_eat(struct config *); | |
92 | +void Configlist_reset(void); | |
66 | 93 | |
67 | 94 | /********* From the file "error.h" ***************************************/ |
68 | 95 | void ErrorMsg(const char *, int,const char *, ...); |
69 | 96 | |
70 | 97 | /****** From the file "option.h" ******************************************/ |
98 | +enum option_type { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR, | |
99 | + OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR}; | |
71 | 100 | struct s_options { |
72 | - enum { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR, | |
73 | - OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR} type; | |
74 | - char *label; | |
101 | + enum option_type type; | |
102 | + const char *label; | |
75 | 103 | char *arg; |
76 | - char *message; | |
104 | + const char *message; | |
77 | 105 | }; |
78 | -int OptInit(/* char**,struct s_options*,FILE* */); | |
79 | -int OptNArgs(/* void */); | |
80 | -char *OptArg(/* int */); | |
81 | -void OptErr(/* int */); | |
82 | -void OptPrint(/* void */); | |
106 | +int OptInit(char**,struct s_options*,FILE*); | |
107 | +int OptNArgs(void); | |
108 | +char *OptArg(int); | |
109 | +void OptErr(int); | |
110 | +void OptPrint(void); | |
83 | 111 | |
84 | 112 | /******** From the file "parse.h" *****************************************/ |
85 | -void Parse(/* struct lemon *lemp */); | |
113 | +void Parse(struct lemon *lemp); | |
86 | 114 | |
87 | 115 | /********* From the file "plink.h" ***************************************/ |
88 | -struct plink *Plink_new(/* void */); | |
89 | -void Plink_add(/* struct plink **, struct config * */); | |
90 | -void Plink_copy(/* struct plink **, struct plink * */); | |
91 | -void Plink_delete(/* struct plink * */); | |
116 | +struct plink *Plink_new(void); | |
117 | +void Plink_add(struct plink **, struct config *); | |
118 | +void Plink_copy(struct plink **, struct plink *); | |
119 | +void Plink_delete(struct plink *); | |
92 | 120 | |
93 | 121 | /********** From the file "report.h" *************************************/ |
94 | -void Reprint(/* struct lemon * */); | |
95 | -void ReportOutput(/* struct lemon * */); | |
96 | -void ReportTable(/* struct lemon * */); | |
97 | -void ReportHeader(/* struct lemon * */); | |
98 | -void CompressTables(/* struct lemon * */); | |
99 | -void ResortStates(/* struct lemon * */); | |
122 | +void Reprint(struct lemon *); | |
123 | +void ReportOutput(struct lemon *); | |
124 | +void ReportTable(struct lemon *, int); | |
125 | +void ReportHeader(struct lemon *); | |
126 | +void CompressTables(struct lemon *); | |
127 | +void ResortStates(struct lemon *); | |
100 | 128 | |
101 | 129 | /********** From the file "set.h" ****************************************/ |
102 | -void SetSize(/* int N */); /* All sets will be of size N */ | |
103 | -char *SetNew(/* void */); /* A new set for element 0..N */ | |
104 | -void SetFree(/* char* */); /* Deallocate a set */ | |
105 | - | |
106 | -int SetAdd(/* char*,int */); /* Add element to a set */ | |
107 | -int SetUnion(/* char *A,char *B */); /* A <- A U B, thru element N */ | |
108 | - | |
130 | +void SetSize(int); /* All sets will be of size N */ | |
131 | +char *SetNew(void); /* A new set for element 0..N */ | |
132 | +void SetFree(char*); /* Deallocate a set */ | |
133 | +int SetAdd(char*,int); /* Add element to a set */ | |
134 | +int SetUnion(char *,char *); /* A <- A U B, thru element N */ | |
109 | 135 | #define SetFind(X,Y) (X[Y]) /* True if Y is in set X */ |
110 | 136 | |
111 | 137 | /********** From the file "struct.h" *************************************/ |
@@ -117,29 +143,32 @@ | ||
117 | 143 | |
118 | 144 | /* Symbols (terminals and nonterminals) of the grammar are stored |
119 | 145 | ** in the following: */ |
120 | -struct symbol { | |
121 | - char *name; /* Name of the symbol */ | |
122 | - int index; /* Index number for this symbol */ | |
123 | - enum { | |
124 | - TERMINAL, | |
125 | - NONTERMINAL, | |
126 | - MULTITERMINAL | |
127 | - } type; /* Symbols are all either TERMINALS or NTs */ | |
128 | - struct rule *rule; /* Linked list of rules of this (if an NT) */ | |
129 | - struct symbol *fallback; /* fallback token in case this token doesn't parse */ | |
130 | - int prec; /* Precedence if defined (-1 otherwise) */ | |
131 | - enum e_assoc { | |
146 | +enum symbol_type { | |
147 | + TERMINAL, | |
148 | + NONTERMINAL, | |
149 | + MULTITERMINAL | |
150 | +}; | |
151 | +enum e_assoc { | |
132 | 152 | LEFT, |
133 | 153 | RIGHT, |
134 | 154 | NONE, |
135 | 155 | UNK |
136 | - } assoc; /* Associativity if predecence is defined */ | |
156 | +}; | |
157 | +struct symbol { | |
158 | + const char *name; /* Name of the symbol */ | |
159 | + int index; /* Index number for this symbol */ | |
160 | + enum symbol_type type; /* Symbols are all either TERMINALS or NTs */ | |
161 | + struct rule *rule; /* Linked list of rules of this (if an NT) */ | |
162 | + struct symbol *fallback; /* fallback token in case this token doesn't parse */ | |
163 | + int prec; /* Precedence if defined (-1 otherwise) */ | |
164 | + enum e_assoc assoc; /* Associativity if precedence is defined */ | |
137 | 165 | char *firstset; /* First-set for all rules of this symbol */ |
138 | 166 | Boolean lambda; /* True if NT and can generate an empty string */ |
139 | 167 | int useCnt; /* Number of times used */ |
140 | 168 | char *destructor; /* Code which executes whenever this symbol is |
141 | 169 | ** popped from the stack during error processing */ |
142 | - int destructorln; /* Line number of destructor code */ | |
170 | + int destLineno; /* Line number for start of destructor. Set to | |
171 | + ** -1 for duplicate destructors. */ | |
143 | 172 | char *datatype; /* The data type of information held by this |
144 | 173 | ** object. Only used if type==NONTERMINAL */ |
145 | 174 | int dtnum; /* The data type number. In the parser, the value |
@@ -154,17 +183,25 @@ | ||
154 | 183 | ** structure. */ |
155 | 184 | struct rule { |
156 | 185 | struct symbol *lhs; /* Left-hand side of the rule */ |
157 | - char *lhsalias; /* Alias for the LHS (NULL if none) */ | |
186 | + const char *lhsalias; /* Alias for the LHS (NULL if none) */ | |
158 | 187 | int lhsStart; /* True if left-hand side is the start symbol */ |
159 | 188 | int ruleline; /* Line number for the rule */ |
160 | 189 | int nrhs; /* Number of RHS symbols */ |
161 | 190 | struct symbol **rhs; /* The RHS symbols */ |
162 | - char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ | |
191 | + const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ | |
163 | 192 | int line; /* Line number at which code begins */ |
164 | - char *code; /* The code executed when this rule is reduced */ | |
193 | + const char *code; /* The code executed when this rule is reduced */ | |
194 | + const char *codePrefix; /* Setup code before code[] above */ | |
195 | + const char *codeSuffix; /* Breakdown code after code[] above */ | |
196 | + int noCode; /* True if this rule has no associated C code */ | |
197 | + int codeEmitted; /* True if the code has been emitted already */ | |
165 | 198 | struct symbol *precsym; /* Precedence symbol for this rule */ |
166 | 199 | int index; /* An index number for this rule */ |
200 | + int iRule; /* Rule number as used in the generated tables */ | |
167 | 201 | Boolean canReduce; /* True if this rule is ever reduced */ |
202 | +#if 0 | |
203 | + Boolean doesReduce; /* Reduce actions occur after optimization */ | |
204 | +#endif | |
168 | 205 | struct rule *nextlhs; /* Next rule with the same LHS */ |
169 | 206 | struct rule *next; /* Next rule in the global list */ |
170 | 207 | }; |
@@ -174,6 +211,10 @@ | ||
174 | 211 | ** Configurations also contain a follow-set which is a list of terminal |
175 | 212 | ** symbols which are allowed to immediately follow the end of the rule. |
176 | 213 | ** Every configuration is recorded as an instance of the following: */ |
214 | +enum cfgstatus { | |
215 | + COMPLETE, | |
216 | + INCOMPLETE | |
217 | +}; | |
177 | 218 | struct config { |
178 | 219 | struct rule *rp; /* The rule upon which the configuration is based */ |
179 | 220 | int dot; /* The parse point */ |
@@ -181,33 +222,34 @@ | ||
181 | 222 | struct plink *fplp; /* Follow-set forward propagation links */ |
182 | 223 | struct plink *bplp; /* Follow-set backwards propagation links */ |
183 | 224 | struct state *stp; /* Pointer to state which contains this */ |
184 | - enum { | |
185 | - COMPLETE, /* The status is used during followset and */ | |
186 | - INCOMPLETE /* shift computations */ | |
187 | - } status; | |
225 | + enum cfgstatus status; /* used during followset and shift computations */ | |
188 | 226 | struct config *next; /* Next configuration in the state */ |
189 | 227 | struct config *bp; /* The next basis configuration */ |
190 | 228 | }; |
191 | 229 | |
230 | +enum e_action { | |
231 | + SHIFT, | |
232 | + ACCEPT, | |
233 | + REDUCE, | |
234 | + ERROR, | |
235 | + SSCONFLICT, /* A shift/shift conflict */ | |
236 | + SRCONFLICT, /* Was a reduce, but part of a conflict */ | |
237 | + RRCONFLICT, /* Was a reduce, but part of a conflict */ | |
238 | + SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ | |
239 | + RD_RESOLVED, /* Was reduce. Precedence resolved conflict */ | |
240 | + NOT_USED, /* Deleted by compression */ | |
241 | + SHIFTREDUCE /* Shift first, then reduce */ | |
242 | +}; | |
243 | + | |
192 | 244 | /* Every shift or reduce operation is stored as one of the following */ |
193 | 245 | struct action { |
194 | 246 | struct symbol *sp; /* The look-ahead symbol */ |
195 | - enum e_action { | |
196 | - SHIFT, | |
197 | - ACCEPT, | |
198 | - REDUCE, | |
199 | - ERROR, | |
200 | - SSCONFLICT, /* A shift/shift conflict */ | |
201 | - SRCONFLICT, /* Was a reduce, but part of a conflict */ | |
202 | - RRCONFLICT, /* Was a reduce, but part of a conflict */ | |
203 | - SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ | |
204 | - RD_RESOLVED, /* Was reduce. Precedence resolved conflict */ | |
205 | - NOT_USED /* Deleted by compression */ | |
206 | - } type; | |
247 | + enum e_action type; | |
207 | 248 | union { |
208 | 249 | struct state *stp; /* The new state, if a shift */ |
209 | 250 | struct rule *rp; /* The rule, if a reduce */ |
210 | 251 | } x; |
252 | + struct symbol *spOpt; /* SHIFTREDUCE optimization to this symbol */ | |
211 | 253 | struct action *next; /* Next action for this state */ |
212 | 254 | struct action *collide; /* Next action with the same hash */ |
213 | 255 | }; |
@@ -217,11 +259,13 @@ | ||
217 | 259 | struct state { |
218 | 260 | struct config *bp; /* The basis configurations for this state */ |
219 | 261 | struct config *cfp; /* All configurations in this set */ |
220 | - int statenum; /* Sequencial number for this state */ | |
221 | - struct action *ap; /* Array of actions for this state */ | |
262 | + int statenum; /* Sequential number for this state */ | |
263 | + struct action *ap; /* List of actions for this state */ | |
222 | 264 | int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ |
223 | 265 | int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ |
224 | - int iDflt; /* Default action */ | |
266 | + int iDfltReduce; /* Default action is to REDUCE by this rule */ | |
267 | + struct rule *pDfltReduce;/* The default REDUCE rule. */ | |
268 | + int autoReduce; /* True if this is an auto-reduce state */ | |
225 | 269 | }; |
226 | 270 | #define NO_OFFSET (-2147483647) |
227 | 271 |
@@ -236,11 +280,13 @@ | ||
236 | 280 | /* The state vector for the entire parser generator is recorded as |
237 | 281 | ** follows. (LEMON uses no global variables and makes little use of |
238 | 282 | ** static variables. Fields in the following structure can be thought |
239 | -** of as begin global variables in the program.) */ | |
283 | +** of as being global variables in the program.) */ | |
240 | 284 | struct lemon { |
241 | 285 | struct state **sorted; /* Table of states sorted by state number */ |
242 | 286 | struct rule *rule; /* List of all rules */ |
287 | + struct rule *startRule; /* First rule */ | |
243 | 288 | int nstate; /* Number of states */ |
289 | + int nxstate; /* nstate with tail degenerate states removed */ | |
244 | 290 | int nrule; /* Number of rules */ |
245 | 291 | int nsymbol; /* Number of terminal and nonterminal symbols */ |
246 | 292 | int nterminal; /* Number of terminal symbols */ |
@@ -255,28 +301,23 @@ | ||
255 | 301 | char *start; /* Name of the start symbol for the grammar */ |
256 | 302 | char *stacksize; /* Size of the parser stack */ |
257 | 303 | char *include; /* Code to put at the start of the C file */ |
258 | - int includeln; /* Line number for start of include code */ | |
259 | 304 | char *error; /* Code to execute when an error is seen */ |
260 | - int errorln; /* Line number for start of error code */ | |
261 | 305 | char *overflow; /* Code to execute on a stack overflow */ |
262 | - int overflowln; /* Line number for start of overflow code */ | |
263 | 306 | char *failure; /* Code to execute on parser failure */ |
264 | - int failureln; /* Line number for start of failure code */ | |
265 | 307 | char *accept; /* Code to execute when the parser excepts */ |
266 | - int acceptln; /* Line number for the start of accept code */ | |
267 | 308 | char *extracode; /* Code appended to the generated file */ |
268 | - int extracodeln; /* Line number for the start of the extra code */ | |
269 | 309 | char *tokendest; /* Code to execute to destroy token data */ |
270 | - int tokendestln; /* Line number for token destroyer code */ | |
271 | 310 | char *vardest; /* Code for the default non-terminal destructor */ |
272 | - int vardestln; /* Line number for default non-term destructor code*/ | |
273 | 311 | char *filename; /* Name of the input file */ |
312 | + char *outbasefilename; /* Name of the input file, with the output dir's path */ | |
274 | 313 | char *outname; /* Name of the current output file */ |
275 | 314 | char *tokenprefix; /* A prefix added to token names in the .h file */ |
276 | 315 | int nconflict; /* Number of parsing conflicts */ |
277 | - int tablesize; /* Size of the parse tables */ | |
316 | + int nactiontab; /* Number of entries in the yy_action[] table */ | |
317 | + int tablesize; /* Total table size of all tables in bytes */ | |
278 | 318 | int basisflag; /* Print only basis configurations */ |
279 | - int has_fallback; /* True if any %fallback is seen in the grammer */ | |
319 | + int has_fallback; /* True if any %fallback is seen in the grammar */ | |
320 | + int nolinenosflag; /* True if #line statements should not be printed */ | |
280 | 321 | char *argv0; /* Name of the program */ |
281 | 322 | }; |
282 | 323 |
@@ -297,41 +338,41 @@ | ||
297 | 338 | /* |
298 | 339 | ** Code for processing tables in the LEMON parser generator. |
299 | 340 | */ |
300 | - | |
301 | 341 | /* Routines for handling a strings */ |
302 | 342 | |
303 | -char *Strsafe(); | |
304 | - | |
305 | -void Strsafe_init(/* void */); | |
306 | -int Strsafe_insert(/* char * */); | |
307 | -char *Strsafe_find(/* char * */); | |
343 | +const char *Strsafe(const char *); | |
344 | + | |
345 | +void Strsafe_init(void); | |
346 | +int Strsafe_insert(const char *); | |
347 | +const char *Strsafe_find(const char *); | |
308 | 348 | |
309 | 349 | /* Routines for handling symbols of the grammar */ |
310 | 350 | |
311 | -struct symbol *Symbol_new(); | |
312 | -int Symbolcmpp(/* struct symbol **, struct symbol ** */); | |
313 | -void Symbol_init(/* void */); | |
314 | -int Symbol_insert(/* struct symbol *, char * */); | |
315 | -struct symbol *Symbol_find(/* char * */); | |
316 | -struct symbol *Symbol_Nth(/* int */); | |
317 | -int Symbol_count(/* */); | |
318 | -struct symbol **Symbol_arrayof(/* */); | |
351 | +struct symbol *Symbol_new(const char *); | |
352 | +int Symbolcmpp(const void *, const void *); | |
353 | +void Symbol_init(void); | |
354 | +int Symbol_insert(struct symbol *, const char *); | |
355 | +struct symbol *Symbol_find(const char *); | |
356 | +struct symbol *Symbol_Nth(int); | |
357 | +int Symbol_count(void); | |
358 | +struct symbol **Symbol_arrayof(void); | |
319 | 359 | |
320 | 360 | /* Routines to manage the state table */ |
321 | 361 | |
322 | -int Configcmp(/* struct config *, struct config * */); | |
323 | -struct state *State_new(); | |
324 | -void State_init(/* void */); | |
325 | -int State_insert(/* struct state *, struct config * */); | |
326 | -struct state *State_find(/* struct config * */); | |
362 | +int Configcmp(const char *, const char *); | |
363 | +struct state *State_new(void); | |
364 | +void State_init(void); | |
365 | +int State_insert(struct state *, struct config *); | |
366 | +struct state *State_find(struct config *); | |
327 | 367 | struct state **State_arrayof(/* */); |
328 | 368 | |
329 | 369 | /* Routines used for efficiency in Configlist_add */ |
330 | 370 | |
331 | -void Configtable_init(/* void */); | |
332 | -int Configtable_insert(/* struct config * */); | |
333 | -struct config *Configtable_find(/* struct config * */); | |
334 | -void Configtable_clear(/* int(*)(struct config *) */); | |
371 | +void Configtable_init(void); | |
372 | +int Configtable_insert(struct config *); | |
373 | +struct config *Configtable_find(struct config *); | |
374 | +void Configtable_clear(int(*)(struct config *)); | |
375 | + | |
335 | 376 | /****************** From the file "action.c" *******************************/ |
336 | 377 | /* |
337 | 378 | ** Routines processing parser actions in the LEMON parser generator. |
@@ -340,7 +381,7 @@ | ||
340 | 381 | /* Allocate a new parser action */ |
341 | 382 | static struct action *Action_new(void){ |
342 | 383 | static struct action *freelist = 0; |
343 | - struct action *new; | |
384 | + struct action *newaction; | |
344 | 385 | |
345 | 386 | if( freelist==0 ){ |
346 | 387 | int i; |
@@ -353,9 +394,9 @@ | ||
353 | 394 | for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; |
354 | 395 | freelist[amt-1].next = 0; |
355 | 396 | } |
356 | - new = freelist; | |
397 | + newaction = freelist; | |
357 | 398 | freelist = freelist->next; |
358 | - return new; | |
399 | + return newaction; | |
359 | 400 | } |
360 | 401 | |
361 | 402 | /* Compare two actions for sorting purposes. Return negative, zero, or |
@@ -371,9 +412,12 @@ | ||
371 | 412 | if( rc==0 ){ |
372 | 413 | rc = (int)ap1->type - (int)ap2->type; |
373 | 414 | } |
374 | - if( rc==0 && ap1->type==REDUCE ){ | |
415 | + if( rc==0 && (ap1->type==REDUCE || ap1->type==SHIFTREDUCE) ){ | |
375 | 416 | rc = ap1->x.rp->index - ap2->x.rp->index; |
376 | 417 | } |
418 | + if( rc==0 ){ | |
419 | + rc = ap2 - ap1; | |
420 | + } | |
377 | 421 | return rc; |
378 | 422 | } |
379 | 423 |
@@ -384,22 +428,23 @@ | ||
384 | 428 | return ap; |
385 | 429 | } |
386 | 430 | |
387 | -void Action_add(app,type,sp,arg) | |
388 | -struct action **app; | |
389 | -enum e_action type; | |
390 | -struct symbol *sp; | |
391 | -char *arg; | |
392 | -{ | |
393 | - struct action *new; | |
394 | - new = Action_new(); | |
395 | - new->next = *app; | |
396 | - *app = new; | |
397 | - new->type = type; | |
398 | - new->sp = sp; | |
431 | +void Action_add( | |
432 | + struct action **app, | |
433 | + enum e_action type, | |
434 | + struct symbol *sp, | |
435 | + char *arg | |
436 | +){ | |
437 | + struct action *newaction; | |
438 | + newaction = Action_new(); | |
439 | + newaction->next = *app; | |
440 | + *app = newaction; | |
441 | + newaction->type = type; | |
442 | + newaction->sp = sp; | |
443 | + newaction->spOpt = 0; | |
399 | 444 | if( type==SHIFT ){ |
400 | - new->x.stp = (struct state *)arg; | |
445 | + newaction->x.stp = (struct state *)arg; | |
401 | 446 | }else{ |
402 | - new->x.rp = (struct rule *)arg; | |
447 | + newaction->x.rp = (struct rule *)arg; | |
403 | 448 | } |
404 | 449 | } |
405 | 450 | /********************** New code to implement the "acttab" module ***********/ |
@@ -409,16 +454,34 @@ | ||
409 | 454 | |
410 | 455 | /* |
411 | 456 | ** The state of the yy_action table under construction is an instance of |
412 | -** the following structure | |
457 | +** the following structure. | |
458 | +** | |
459 | +** The yy_action table maps the pair (state_number, lookahead) into an | |
460 | +** action_number. The table is an array of integers pairs. The state_number | |
461 | +** determines an initial offset into the yy_action array. The lookahead | |
462 | +** value is then added to this initial offset to get an index X into the | |
463 | +** yy_action array. If the aAction[X].lookahead equals the value of the | |
464 | +** of the lookahead input, then the value of the action_number output is | |
465 | +** aAction[X].action. If the lookaheads do not match then the | |
466 | +** default action for the state_number is returned. | |
467 | +** | |
468 | +** All actions associated with a single state_number are first entered | |
469 | +** into aLookahead[] using multiple calls to acttab_action(). Then the | |
470 | +** actions for that single state_number are placed into the aAction[] | |
471 | +** array with a single call to acttab_insert(). The acttab_insert() call | |
472 | +** also resets the aLookahead[] array in preparation for the next | |
473 | +** state number. | |
413 | 474 | */ |
475 | +struct lookahead_action { | |
476 | + int lookahead; /* Value of the lookahead token */ | |
477 | + int action; /* Action to take on the given lookahead */ | |
478 | +}; | |
414 | 479 | typedef struct acttab acttab; |
415 | 480 | struct acttab { |
416 | 481 | int nAction; /* Number of used slots in aAction[] */ |
417 | 482 | int nActionAlloc; /* Slots allocated for aAction[] */ |
418 | - struct { | |
419 | - int lookahead; /* Value of the lookahead token */ | |
420 | - int action; /* Action to take on the given lookahead */ | |
421 | - } *aAction, /* The yy_action[] table under construction */ | |
483 | + struct lookahead_action | |
484 | + *aAction, /* The yy_action[] table under construction */ | |
422 | 485 | *aLookahead; /* A single new transaction set */ |
423 | 486 | int mnLookahead; /* Minimum aLookahead[].lookahead */ |
424 | 487 | int mnAction; /* Action associated with mnLookahead */ |
@@ -437,7 +500,8 @@ | ||
437 | 500 | #define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead) |
438 | 501 | |
439 | 502 | /* Free all memory associated with the given acttab */ |
440 | -void acttab_free(acttab *p){ | |
503 | +void acttab_free(acttab **pp){ | |
504 | + acttab *p = *pp; | |
441 | 505 | free( p->aAction ); |
442 | 506 | free( p->aLookahead ); |
443 | 507 | free( p ); |
@@ -445,7 +509,7 @@ | ||
445 | 509 | |
446 | 510 | /* Allocate a new acttab structure */ |
447 | 511 | acttab *acttab_alloc(void){ |
448 | - acttab *p = calloc( 1, sizeof(*p) ); | |
512 | + acttab *p = (acttab *) calloc( 1, sizeof(*p) ); | |
449 | 513 | if( p==0 ){ |
450 | 514 | fprintf(stderr,"Unable to allocate memory for a new acttab."); |
451 | 515 | exit(1); |
@@ -454,12 +518,15 @@ | ||
454 | 518 | return p; |
455 | 519 | } |
456 | 520 | |
457 | -/* Add a new action to the current transaction set | |
521 | +/* Add a new action to the current transaction set. | |
522 | +** | |
523 | +** This routine is called once for each lookahead for a particular | |
524 | +** state. | |
458 | 525 | */ |
459 | 526 | void acttab_action(acttab *p, int lookahead, int action){ |
460 | 527 | if( p->nLookahead>=p->nLookaheadAlloc ){ |
461 | 528 | p->nLookaheadAlloc += 25; |
462 | - p->aLookahead = realloc( p->aLookahead, | |
529 | + p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead, | |
463 | 530 | sizeof(p->aLookahead[0])*p->nLookaheadAlloc ); |
464 | 531 | if( p->aLookahead==0 ){ |
465 | 532 | fprintf(stderr,"malloc failed\n"); |
@@ -501,7 +568,7 @@ | ||
501 | 568 | if( p->nAction + n >= p->nActionAlloc ){ |
502 | 569 | int oldAlloc = p->nActionAlloc; |
503 | 570 | p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20; |
504 | - p->aAction = realloc( p->aAction, | |
571 | + p->aAction = (struct lookahead_action *) realloc( p->aAction, | |
505 | 572 | sizeof(p->aAction[0])*p->nActionAlloc); |
506 | 573 | if( p->aAction==0 ){ |
507 | 574 | fprintf(stderr,"malloc failed\n"); |
@@ -513,28 +580,16 @@ | ||
513 | 580 | } |
514 | 581 | } |
515 | 582 | |
516 | - /* Scan the existing action table looking for an offset where we can | |
517 | - ** insert the current transaction set. Fall out of the loop when that | |
518 | - ** offset is found. In the worst case, we fall out of the loop when | |
519 | - ** i reaches p->nAction, which means we append the new transaction set. | |
583 | + /* Scan the existing action table looking for an offset that is a | |
584 | + ** duplicate of the current transaction set. Fall out of the loop | |
585 | + ** if and when the duplicate is found. | |
520 | 586 | ** |
521 | 587 | ** i is the index in p->aAction[] where p->mnLookahead is inserted. |
522 | 588 | */ |
523 | - for(i=0; i<p->nAction+p->mnLookahead; i++){ | |
524 | - if( p->aAction[i].lookahead<0 ){ | |
525 | - for(j=0; j<p->nLookahead; j++){ | |
526 | - k = p->aLookahead[j].lookahead - p->mnLookahead + i; | |
527 | - if( k<0 ) break; | |
528 | - if( p->aAction[k].lookahead>=0 ) break; | |
529 | - } | |
530 | - if( j<p->nLookahead ) continue; | |
531 | - for(j=0; j<p->nAction; j++){ | |
532 | - if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break; | |
533 | - } | |
534 | - if( j==p->nAction ){ | |
535 | - break; /* Fits in empty slots */ | |
536 | - } | |
537 | - }else if( p->aAction[i].lookahead==p->mnLookahead ){ | |
589 | + for(i=p->nAction-1; i>=0; i--){ | |
590 | + if( p->aAction[i].lookahead==p->mnLookahead ){ | |
591 | + /* All lookaheads and actions in the aLookahead[] transaction | |
592 | + ** must match against the candidate aAction[i] entry. */ | |
538 | 593 | if( p->aAction[i].action!=p->mnAction ) continue; |
539 | 594 | for(j=0; j<p->nLookahead; j++){ |
540 | 595 | k = p->aLookahead[j].lookahead - p->mnLookahead + i; |
@@ -543,13 +598,43 @@ | ||
543 | 598 | if( p->aLookahead[j].action!=p->aAction[k].action ) break; |
544 | 599 | } |
545 | 600 | if( j<p->nLookahead ) continue; |
601 | + | |
602 | + /* No possible lookahead value that is not in the aLookahead[] | |
603 | + ** transaction is allowed to match aAction[i] */ | |
546 | 604 | n = 0; |
547 | 605 | for(j=0; j<p->nAction; j++){ |
548 | 606 | if( p->aAction[j].lookahead<0 ) continue; |
549 | 607 | if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++; |
550 | 608 | } |
551 | 609 | if( n==p->nLookahead ){ |
552 | - break; /* Same as a prior transaction set */ | |
610 | + break; /* An exact match is found at offset i */ | |
611 | + } | |
612 | + } | |
613 | + } | |
614 | + | |
615 | + /* If no existing offsets exactly match the current transaction, find an | |
616 | + ** an empty offset in the aAction[] table in which we can add the | |
617 | + ** aLookahead[] transaction. | |
618 | + */ | |
619 | + if( i<0 ){ | |
620 | + /* Look for holes in the aAction[] table that fit the current | |
621 | + ** aLookahead[] transaction. Leave i set to the offset of the hole. | |
622 | + ** If no holes are found, i is left at p->nAction, which means the | |
623 | + ** transaction will be appended. */ | |
624 | + for(i=0; i<p->nActionAlloc - p->mxLookahead; i++){ | |
625 | + if( p->aAction[i].lookahead<0 ){ | |
626 | + for(j=0; j<p->nLookahead; j++){ | |
627 | + k = p->aLookahead[j].lookahead - p->mnLookahead + i; | |
628 | + if( k<0 ) break; | |
629 | + if( p->aAction[k].lookahead>=0 ) break; | |
630 | + } | |
631 | + if( j<p->nLookahead ) continue; | |
632 | + for(j=0; j<p->nAction; j++){ | |
633 | + if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break; | |
634 | + } | |
635 | + if( j==p->nAction ){ | |
636 | + break; /* Fits in empty slots */ | |
637 | + } | |
553 | 638 | } |
554 | 639 | } |
555 | 640 | } |
@@ -581,8 +666,7 @@ | ||
581 | 666 | ** are not RHS symbols with a defined precedence, the precedence |
582 | 667 | ** symbol field is left blank. |
583 | 668 | */ |
584 | -void FindRulePrecedences(xp) | |
585 | -struct lemon *xp; | |
669 | +void FindRulePrecedences(struct lemon *xp) | |
586 | 670 | { |
587 | 671 | struct rule *rp; |
588 | 672 | for(rp=xp->rule; rp; rp=rp->next){ |
@@ -611,8 +695,7 @@ | ||
611 | 695 | ** The first set is the set of all terminal symbols which can begin |
612 | 696 | ** a string generated by that nonterminal. |
613 | 697 | */ |
614 | -void FindFirstSets(lemp) | |
615 | -struct lemon *lemp; | |
698 | +void FindFirstSets(struct lemon *lemp) | |
616 | 699 | { |
617 | 700 | int i, j; |
618 | 701 | struct rule *rp; |
@@ -632,7 +715,8 @@ | ||
632 | 715 | if( rp->lhs->lambda ) continue; |
633 | 716 | for(i=0; i<rp->nrhs; i++){ |
634 | 717 | struct symbol *sp = rp->rhs[i]; |
635 | - if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break; | |
718 | + assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE ); | |
719 | + if( sp->lambda==LEMON_FALSE ) break; | |
636 | 720 | } |
637 | 721 | if( i==rp->nrhs ){ |
638 | 722 | rp->lhs->lambda = LEMON_TRUE; |
@@ -673,9 +757,8 @@ | ||
673 | 757 | ** are added to between some states so that the LR(1) follow sets |
674 | 758 | ** can be computed later. |
675 | 759 | */ |
676 | -PRIVATE struct state *getstate(/* struct lemon * */); /* forward reference */ | |
677 | -void FindStates(lemp) | |
678 | -struct lemon *lemp; | |
760 | +PRIVATE struct state *getstate(struct lemon *); /* forward reference */ | |
761 | +void FindStates(struct lemon *lemp) | |
679 | 762 | { |
680 | 763 | struct symbol *sp; |
681 | 764 | struct rule *rp; |
@@ -689,12 +772,12 @@ | ||
689 | 772 | ErrorMsg(lemp->filename,0, |
690 | 773 | "The specified start symbol \"%s\" is not \ |
691 | 774 | in a nonterminal of the grammar. \"%s\" will be used as the start \ |
692 | -symbol instead.",lemp->start,lemp->rule->lhs->name); | |
775 | +symbol instead.",lemp->start,lemp->startRule->lhs->name); | |
693 | 776 | lemp->errorcnt++; |
694 | - sp = lemp->rule->lhs; | |
777 | + sp = lemp->startRule->lhs; | |
695 | 778 | } |
696 | 779 | }else{ |
697 | - sp = lemp->rule->lhs; | |
780 | + sp = lemp->startRule->lhs; | |
698 | 781 | } |
699 | 782 | |
700 | 783 | /* Make sure the start symbol doesn't occur on the right-hand side of |
@@ -733,9 +816,8 @@ | ||
733 | 816 | /* Return a pointer to a state which is described by the configuration |
734 | 817 | ** list which has been built from calls to Configlist_add. |
735 | 818 | */ |
736 | -PRIVATE void buildshifts(/* struct lemon *, struct state * */); /* Forwd ref */ | |
737 | -PRIVATE struct state *getstate(lemp) | |
738 | -struct lemon *lemp; | |
819 | +PRIVATE void buildshifts(struct lemon *, struct state *); /* Forwd ref */ | |
820 | +PRIVATE struct state *getstate(struct lemon *lemp) | |
739 | 821 | { |
740 | 822 | struct config *cfp, *bp; |
741 | 823 | struct state *stp; |
@@ -779,9 +861,7 @@ | ||
779 | 861 | /* |
780 | 862 | ** Return true if two symbols are the same. |
781 | 863 | */ |
782 | -int same_symbol(a,b) | |
783 | -struct symbol *a; | |
784 | -struct symbol *b; | |
864 | +int same_symbol(struct symbol *a, struct symbol *b) | |
785 | 865 | { |
786 | 866 | int i; |
787 | 867 | if( a==b ) return 1; |
@@ -797,13 +877,11 @@ | ||
797 | 877 | /* Construct all successor states to the given state. A "successor" |
798 | 878 | ** state is any state which can be reached by a shift action. |
799 | 879 | */ |
800 | -PRIVATE void buildshifts(lemp,stp) | |
801 | -struct lemon *lemp; | |
802 | -struct state *stp; /* The state from which successors are computed */ | |
880 | +PRIVATE void buildshifts(struct lemon *lemp, struct state *stp) | |
803 | 881 | { |
804 | 882 | struct config *cfp; /* For looping thru the config closure of "stp" */ |
805 | 883 | struct config *bcfp; /* For the inner loop on config closure of "stp" */ |
806 | - struct config *new; /* */ | |
884 | + struct config *newcfg; /* */ | |
807 | 885 | struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ |
808 | 886 | struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ |
809 | 887 | struct state *newstp; /* A pointer to a successor state */ |
@@ -828,8 +906,8 @@ | ||
828 | 906 | bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */ |
829 | 907 | if( !same_symbol(bsp,sp) ) continue; /* Must be same as for "cfp" */ |
830 | 908 | bcfp->status = COMPLETE; /* Mark this config as used */ |
831 | - new = Configlist_addbasis(bcfp->rp,bcfp->dot+1); | |
832 | - Plink_add(&new->bplp,bcfp); | |
909 | + newcfg = Configlist_addbasis(bcfp->rp,bcfp->dot+1); | |
910 | + Plink_add(&newcfg->bplp,bcfp); | |
833 | 911 | } |
834 | 912 | |
835 | 913 | /* Get a pointer to the state described by the basis configuration set |
@@ -852,8 +930,7 @@ | ||
852 | 930 | /* |
853 | 931 | ** Construct the propagation links |
854 | 932 | */ |
855 | -void FindLinks(lemp) | |
856 | -struct lemon *lemp; | |
933 | +void FindLinks(struct lemon *lemp) | |
857 | 934 | { |
858 | 935 | int i; |
859 | 936 | struct config *cfp, *other; |
@@ -888,8 +965,7 @@ | ||
888 | 965 | ** A followset is the set of all symbols which can come immediately |
889 | 966 | ** after a configuration. |
890 | 967 | */ |
891 | -void FindFollowSets(lemp) | |
892 | -struct lemon *lemp; | |
968 | +void FindFollowSets(struct lemon *lemp) | |
893 | 969 | { |
894 | 970 | int i; |
895 | 971 | struct config *cfp; |
@@ -921,12 +997,11 @@ | ||
921 | 997 | }while( progress ); |
922 | 998 | } |
923 | 999 | |
924 | -static int resolve_conflict(); | |
1000 | +static int resolve_conflict(struct action *,struct action *); | |
925 | 1001 | |
926 | 1002 | /* Compute the reduce actions, and resolve conflicts. |
927 | 1003 | */ |
928 | -void FindActions(lemp) | |
929 | -struct lemon *lemp; | |
1004 | +void FindActions(struct lemon *lemp) | |
930 | 1005 | { |
931 | 1006 | int i,j; |
932 | 1007 | struct config *cfp; |
@@ -956,9 +1031,9 @@ | ||
956 | 1031 | /* Add the accepting token */ |
957 | 1032 | if( lemp->start ){ |
958 | 1033 | sp = Symbol_find(lemp->start); |
959 | - if( sp==0 ) sp = lemp->rule->lhs; | |
1034 | + if( sp==0 ) sp = lemp->startRule->lhs; | |
960 | 1035 | }else{ |
961 | - sp = lemp->rule->lhs; | |
1036 | + sp = lemp->startRule->lhs; | |
962 | 1037 | } |
963 | 1038 | /* Add to the first state (which is always the starting state of the |
964 | 1039 | ** finite state machine) an action to ACCEPT if the lookahead is the |
@@ -976,7 +1051,7 @@ | ||
976 | 1051 | for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){ |
977 | 1052 | /* The two actions "ap" and "nap" have the same lookahead. |
978 | 1053 | ** Figure out which one should be used */ |
979 | - lemp->nconflict += resolve_conflict(ap,nap,lemp->errsym); | |
1054 | + lemp->nconflict += resolve_conflict(ap,nap); | |
980 | 1055 | } |
981 | 1056 | } |
982 | 1057 | } |
@@ -997,7 +1072,7 @@ | ||
997 | 1072 | } |
998 | 1073 | |
999 | 1074 | /* Resolve a conflict between the two given actions. If the |
1000 | -** conflict can't be resolve, return non-zero. | |
1075 | +** conflict can't be resolved, return non-zero. | |
1001 | 1076 | ** |
1002 | 1077 | ** NO LONGER TRUE: |
1003 | 1078 | ** To resolve a conflict, first look to see if either action |
@@ -1009,11 +1084,10 @@ | ||
1009 | 1084 | ** If either action is a SHIFT, then it must be apx. This |
1010 | 1085 | ** function won't work if apx->type==REDUCE and apy->type==SHIFT. |
1011 | 1086 | */ |
1012 | -static int resolve_conflict(apx,apy,errsym) | |
1013 | -struct action *apx; | |
1014 | -struct action *apy; | |
1015 | -struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */ | |
1016 | -{ | |
1087 | +static int resolve_conflict( | |
1088 | + struct action *apx, | |
1089 | + struct action *apy | |
1090 | +){ | |
1017 | 1091 | struct symbol *spx, *spy; |
1018 | 1092 | int errcnt = 0; |
1019 | 1093 | assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */ |
@@ -1028,7 +1102,7 @@ | ||
1028 | 1102 | /* Not enough precedence information. */ |
1029 | 1103 | apy->type = SRCONFLICT; |
1030 | 1104 | errcnt++; |
1031 | - }else if( spx->prec>spy->prec ){ /* Lower precedence wins */ | |
1105 | + }else if( spx->prec>spy->prec ){ /* higher precedence wins */ | |
1032 | 1106 | apy->type = RD_RESOLVED; |
1033 | 1107 | }else if( spx->prec<spy->prec ){ |
1034 | 1108 | apx->type = SH_RESOLVED; |
@@ -1038,8 +1112,7 @@ | ||
1038 | 1112 | apx->type = SH_RESOLVED; |
1039 | 1113 | }else{ |
1040 | 1114 | assert( spx->prec==spy->prec && spx->assoc==NONE ); |
1041 | - apy->type = SRCONFLICT; | |
1042 | - errcnt++; | |
1115 | + apy->type = ERROR; | |
1043 | 1116 | } |
1044 | 1117 | }else if( apx->type==REDUCE && apy->type==REDUCE ){ |
1045 | 1118 | spx = apx->x.rp->precsym; |
@@ -1086,7 +1159,7 @@ | ||
1086 | 1159 | |
1087 | 1160 | /* Return a pointer to a new configuration */ |
1088 | 1161 | PRIVATE struct config *newconfig(){ |
1089 | - struct config *new; | |
1162 | + struct config *newcfg; | |
1090 | 1163 | if( freelist==0 ){ |
1091 | 1164 | int i; |
1092 | 1165 | int amt = 3; |
@@ -1098,14 +1171,13 @@ | ||
1098 | 1171 | for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; |
1099 | 1172 | freelist[amt-1].next = 0; |
1100 | 1173 | } |
1101 | - new = freelist; | |
1174 | + newcfg = freelist; | |
1102 | 1175 | freelist = freelist->next; |
1103 | - return new; | |
1176 | + return newcfg; | |
1104 | 1177 | } |
1105 | 1178 | |
1106 | 1179 | /* The configuration "old" is no longer used */ |
1107 | -PRIVATE void deleteconfig(old) | |
1108 | -struct config *old; | |
1180 | +PRIVATE void deleteconfig(struct config *old) | |
1109 | 1181 | { |
1110 | 1182 | old->next = freelist; |
1111 | 1183 | freelist = old; |
@@ -1132,10 +1204,10 @@ | ||
1132 | 1204 | } |
1133 | 1205 | |
1134 | 1206 | /* Add another configuration to the configuration list */ |
1135 | -struct config *Configlist_add(rp,dot) | |
1136 | -struct rule *rp; /* The rule */ | |
1137 | -int dot; /* Index into the RHS of the rule where the dot goes */ | |
1138 | -{ | |
1207 | +struct config *Configlist_add( | |
1208 | + struct rule *rp, /* The rule */ | |
1209 | + int dot /* Index into the RHS of the rule where the dot goes */ | |
1210 | +){ | |
1139 | 1211 | struct config *cfp, model; |
1140 | 1212 | |
1141 | 1213 | assert( currentend!=0 ); |
@@ -1159,9 +1231,7 @@ | ||
1159 | 1231 | } |
1160 | 1232 | |
1161 | 1233 | /* Add a basis configuration to the configuration list */ |
1162 | -struct config *Configlist_addbasis(rp,dot) | |
1163 | -struct rule *rp; | |
1164 | -int dot; | |
1234 | +struct config *Configlist_addbasis(struct rule *rp, int dot) | |
1165 | 1235 | { |
1166 | 1236 | struct config *cfp, model; |
1167 | 1237 |
@@ -1189,8 +1259,7 @@ | ||
1189 | 1259 | } |
1190 | 1260 | |
1191 | 1261 | /* Compute the closure of the configuration list */ |
1192 | -void Configlist_closure(lemp) | |
1193 | -struct lemon *lemp; | |
1262 | +void Configlist_closure(struct lemon *lemp) | |
1194 | 1263 | { |
1195 | 1264 | struct config *cfp, *newcfp; |
1196 | 1265 | struct rule *rp, *newrp; |
@@ -1236,14 +1305,16 @@ | ||
1236 | 1305 | |
1237 | 1306 | /* Sort the configuration list */ |
1238 | 1307 | void Configlist_sort(){ |
1239 | - current = (struct config *)msort(current,&(current->next),Configcmp); | |
1308 | + current = (struct config*)msort((char*)current,(char**)&(current->next), | |
1309 | + Configcmp); | |
1240 | 1310 | currentend = 0; |
1241 | 1311 | return; |
1242 | 1312 | } |
1243 | 1313 | |
1244 | 1314 | /* Sort the basis configuration list */ |
1245 | 1315 | void Configlist_sortbasis(){ |
1246 | - basis = (struct config *)msort(current,&(current->bp),Configcmp); | |
1316 | + basis = (struct config *)msort((char*)current,(char**)&(current->bp), | |
1317 | + Configcmp); | |
1247 | 1318 | basisend = 0; |
1248 | 1319 | return; |
1249 | 1320 | } |
@@ -1269,8 +1340,7 @@ | ||
1269 | 1340 | } |
1270 | 1341 | |
1271 | 1342 | /* Free all elements of the given configuration list */ |
1272 | -void Configlist_eat(cfp) | |
1273 | -struct config *cfp; | |
1343 | +void Configlist_eat(struct config *cfp) | |
1274 | 1344 | { |
1275 | 1345 | struct config *nextcfp; |
1276 | 1346 | for(; cfp; cfp=nextcfp){ |
@@ -1287,84 +1357,26 @@ | ||
1287 | 1357 | ** Code for printing error message. |
1288 | 1358 | */ |
1289 | 1359 | |
1290 | -/* Find a good place to break "msg" so that its length is at least "min" | |
1291 | -** but no more than "max". Make the point as close to max as possible. | |
1292 | -*/ | |
1293 | -static int findbreak(msg,min,max) | |
1294 | -char *msg; | |
1295 | -int min; | |
1296 | -int max; | |
1297 | -{ | |
1298 | - int i,spot; | |
1299 | - char c; | |
1300 | - for(i=spot=min; i<=max; i++){ | |
1301 | - c = msg[i]; | |
1302 | - if( c=='\t' ) msg[i] = ' '; | |
1303 | - if( c=='\n' ){ msg[i] = ' '; spot = i; break; } | |
1304 | - if( c==0 ){ spot = i; break; } | |
1305 | - if( c=='-' && i<max-1 ) spot = i+1; | |
1306 | - if( c==' ' ) spot = i; | |
1307 | - } | |
1308 | - return spot; | |
1309 | -} | |
1310 | - | |
1311 | -/* | |
1312 | -** The error message is split across multiple lines if necessary. The | |
1313 | -** splits occur at a space, if there is a space available near the end | |
1314 | -** of the line. | |
1315 | -*/ | |
1316 | -#define ERRMSGSIZE 10000 /* Hope this is big enough. No way to error check */ | |
1317 | -#if _MSC_VER | |
1318 | -#define LINEWIDTH 10000 /* Max width of any output line */ | |
1319 | -#else | |
1320 | -#define LINEWIDTH 79 /* Max width of any output line */ | |
1321 | -#endif | |
1322 | -#define PREFIXLIMIT 3000 /* Max width of the prefix on each line */ | |
1323 | 1360 | void ErrorMsg(const char *filename, int lineno, const char *format, ...){ |
1324 | - char errmsg[ERRMSGSIZE]; | |
1325 | - char prefix[PREFIXLIMIT+10]; | |
1326 | - size_t errmsgsize; | |
1327 | - size_t prefixsize; | |
1328 | - size_t availablewidth; | |
1329 | 1361 | va_list ap; |
1330 | - int end, restart, base; | |
1331 | - | |
1332 | - va_start(ap, format); | |
1333 | - /* Prepare a prefix to be prepended to every output line */ | |
1362 | + | |
1334 | 1363 | #if _MSC_VER |
1335 | 1364 | if( lineno>0 ){ |
1336 | - sprintf(prefix,"%.*s(%d) : error : ",PREFIXLIMIT-10,filename,lineno); | |
1365 | + fprintf(stderr,"%s(%d) : error : ",filename,lineno); | |
1337 | 1366 | }else{ |
1338 | - sprintf(prefix,"%.*s : error : ",PREFIXLIMIT-10,filename); | |
1367 | + fprintf(stderr,"%s : error : ",filename); | |
1339 | 1368 | } |
1340 | 1369 | #else |
1341 | 1370 | if( lineno>0 ){ |
1342 | - sprintf(prefix,"%.*s:%d: ",PREFIXLIMIT-10,filename,lineno); | |
1371 | + fprintf(stderr,"%s:%d: ",filename,lineno); | |
1343 | 1372 | }else{ |
1344 | - sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename); | |
1373 | + fprintf(stderr,"%s: ",filename); | |
1345 | 1374 | } |
1346 | 1375 | #endif |
1347 | - prefixsize = strlen(prefix); | |
1348 | - availablewidth = LINEWIDTH - prefixsize; | |
1349 | - | |
1350 | - /* Generate the error message */ | |
1351 | - vsprintf(errmsg,format,ap); | |
1376 | + va_start(ap, format); | |
1377 | + vfprintf(stderr,format,ap); | |
1352 | 1378 | va_end(ap); |
1353 | - errmsgsize = strlen(errmsg); | |
1354 | - /* Remove trailing '\n's from the error message. */ | |
1355 | - while( errmsgsize>0 && errmsg[errmsgsize-1]=='\n' ){ | |
1356 | - errmsg[--errmsgsize] = 0; | |
1357 | - } | |
1358 | - | |
1359 | - /* Print the error message */ | |
1360 | - base = 0; | |
1361 | - while( errmsg[base]!=0 ){ | |
1362 | - end = restart = findbreak(&errmsg[base],0,availablewidth); | |
1363 | - restart += base; | |
1364 | - while( errmsg[restart]==' ' ) restart++; | |
1365 | - fprintf(stdout,"%s%.*s\n",prefix,end,&errmsg[base]); | |
1366 | - base = restart; | |
1367 | - } | |
1379 | + fprintf(stderr, "\n"); | |
1368 | 1380 | } |
1369 | 1381 | /**************** From the file "main.c" ************************************/ |
1370 | 1382 | /* |
@@ -1388,13 +1400,13 @@ | ||
1388 | 1400 | static void handle_D_option(char *z){ |
1389 | 1401 | char **paz; |
1390 | 1402 | nDefine++; |
1391 | - azDefine = realloc(azDefine, sizeof(azDefine[0])*nDefine); | |
1403 | + azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine); | |
1392 | 1404 | if( azDefine==0 ){ |
1393 | 1405 | fprintf(stderr,"out of memory\n"); |
1394 | 1406 | exit(1); |
1395 | 1407 | } |
1396 | 1408 | paz = &azDefine[nDefine-1]; |
1397 | - *paz = malloc( strlen(z)+1 ); | |
1409 | + *paz = (char *) malloc( lemonStrlen(z)+1 ); | |
1398 | 1410 | if( *paz==0 ){ |
1399 | 1411 | fprintf(stderr,"out of memory\n"); |
1400 | 1412 | exit(1); |
@@ -1404,11 +1416,143 @@ | ||
1404 | 1416 | *z = 0; |
1405 | 1417 | } |
1406 | 1418 | |
1419 | +static char *user_templatename = NULL; | |
1420 | +static void handle_T_option(char *z){ | |
1421 | + user_templatename = (char *) malloc( lemonStrlen(z)+1 ); | |
1422 | + if( user_templatename==0 ){ | |
1423 | + memory_error(); | |
1424 | + } | |
1425 | + strcpy(user_templatename, z); | |
1426 | +} | |
1427 | + | |
1428 | +/* Routines for routing output to a different directory than the one | |
1429 | +** the source file resides in. | |
1430 | +*/ | |
1431 | +static char *output_dir = NULL; | |
1432 | + | |
1433 | +static inline Boolean is_seperator(int c) | |
1434 | +{ | |
1435 | + if (c == '/') | |
1436 | + return LEMON_TRUE; | |
1437 | +#if defined(_WIN32) || defined(DOS) | |
1438 | + if (c == '\\' || c == ':') | |
1439 | + return LEMON_TRUE; | |
1440 | +#endif | |
1441 | + return LEMON_FALSE; | |
1442 | +} | |
1443 | + | |
1444 | +/* Returns the file part of a pathname. | |
1445 | +*/ | |
1446 | +const char *file_base(const char *path) | |
1447 | +{ | |
1448 | + const char *src = path + strlen(path) - 1; | |
1449 | + if( src >= path ){ | |
1450 | + // back up until a / or the start | |
1451 | + while (src != path && !is_seperator(*(src - 1))) | |
1452 | + src--; | |
1453 | + | |
1454 | + // Check for files with drive specification but no path | |
1455 | +#if defined(_WIN32) || defined(DOS) | |
1456 | + if( src == path && src[0] != 0 ){ | |
1457 | + if( src[1] == ':' ) | |
1458 | + src += 2; | |
1459 | + } | |
1460 | +#endif | |
1461 | + return src; | |
1462 | + } | |
1463 | + return NULL; | |
1464 | +} | |
1465 | + | |
1466 | +static char *stitch_outdir(char *path) | |
1467 | +{ | |
1468 | + if( output_dir ){ | |
1469 | + const char *base = file_base(path); | |
1470 | + char *newpath = (char *) malloc( lemonStrlen(output_dir) + lemonStrlen(path) + 1 ); | |
1471 | + if( newpath==0 ){ | |
1472 | + memory_error(); | |
1473 | + } | |
1474 | + strcpy(newpath, output_dir); | |
1475 | + strcat(newpath, base); | |
1476 | + return newpath; | |
1477 | + } | |
1478 | + return path; | |
1479 | +} | |
1480 | + | |
1481 | +static void handle_C_option(char *z){ | |
1482 | + int len = lemonStrlen(z); | |
1483 | + output_dir = (char *) malloc( len+2 ); | |
1484 | + if( output_dir==0 ){ | |
1485 | + memory_error(); | |
1486 | + } | |
1487 | + strcpy(output_dir, z); | |
1488 | + if( !is_seperator(output_dir[len-1]) ){ | |
1489 | + output_dir[len] = '/'; | |
1490 | + output_dir[len+1] = '\0'; | |
1491 | + } | |
1492 | +} | |
1493 | + | |
1494 | +/* Merge together to lists of rules ordered by rule.iRule */ | |
1495 | +static struct rule *Rule_merge(struct rule *pA, struct rule *pB){ | |
1496 | + struct rule *pFirst = 0; | |
1497 | + struct rule **ppPrev = &pFirst; | |
1498 | + while( pA && pB ){ | |
1499 | + if( pA->iRule<pB->iRule ){ | |
1500 | + *ppPrev = pA; | |
1501 | + ppPrev = &pA->next; | |
1502 | + pA = pA->next; | |
1503 | + }else{ | |
1504 | + *ppPrev = pB; | |
1505 | + ppPrev = &pB->next; | |
1506 | + pB = pB->next; | |
1507 | + } | |
1508 | + } | |
1509 | + if( pA ){ | |
1510 | + *ppPrev = pA; | |
1511 | + }else{ | |
1512 | + *ppPrev = pB; | |
1513 | + } | |
1514 | + return pFirst; | |
1515 | +} | |
1516 | + | |
1517 | +/* | |
1518 | +** Sort a list of rules in order of increasing iRule value | |
1519 | +*/ | |
1520 | +static struct rule *Rule_sort(struct rule *rp){ | |
1521 | + int i; | |
1522 | + struct rule *pNext; | |
1523 | + struct rule *x[32]; | |
1524 | + memset(x, 0, sizeof(x)); | |
1525 | + while( rp ){ | |
1526 | + pNext = rp->next; | |
1527 | + rp->next = 0; | |
1528 | + for(i=0; i<sizeof(x)/sizeof(x[0]) && x[i]; i++){ | |
1529 | + rp = Rule_merge(x[i], rp); | |
1530 | + x[i] = 0; | |
1531 | + } | |
1532 | + x[i] = rp; | |
1533 | + rp = pNext; | |
1534 | + } | |
1535 | + rp = 0; | |
1536 | + for(i=0; i<sizeof(x)/sizeof(x[0]); i++){ | |
1537 | + rp = Rule_merge(x[i], rp); | |
1538 | + } | |
1539 | + return rp; | |
1540 | +} | |
1541 | + | |
1542 | +/* forward reference */ | |
1543 | +static const char *minimum_size_type(int lwr, int upr, int *pnByte); | |
1544 | + | |
1545 | +/* Print a single line of the "Parser Stats" output | |
1546 | +*/ | |
1547 | +static void stats_line(const char *zLabel, int iValue){ | |
1548 | + int nLabel = lemonStrlen(zLabel); | |
1549 | + printf(" %s%.*s %5d\n", zLabel, | |
1550 | + 35-nLabel, "................................", | |
1551 | + iValue); | |
1552 | +} | |
1407 | 1553 | |
1408 | 1554 | /* The main program. Parse the command line and do it... */ |
1409 | -int main(argc,argv) | |
1410 | -int argc; | |
1411 | -char **argv; | |
1555 | +int main(int argc, char **argv) | |
1412 | 1556 | { |
1413 | 1557 | static int version = 0; |
1414 | 1558 | static int rpflag = 0; |
@@ -1417,20 +1561,33 @@ | ||
1417 | 1561 | static int quiet = 0; |
1418 | 1562 | static int statistics = 0; |
1419 | 1563 | static int mhflag = 0; |
1564 | + static int nolinenosflag = 0; | |
1565 | + static int noResort = 0; | |
1420 | 1566 | static struct s_options options[] = { |
1421 | 1567 | {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, |
1422 | 1568 | {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, |
1569 | + {OPT_FSTR, "C", (char*)handle_C_option, "Write output files to a different directory."}, | |
1423 | 1570 | {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, |
1571 | + {OPT_FSTR, "f", 0, "Ignored. (Placeholder for -f compiler options.)"}, | |
1424 | 1572 | {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, |
1425 | - {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file"}, | |
1573 | + {OPT_FSTR, "I", 0, "Ignored. (Placeholder for '-I' compiler options.)"}, | |
1574 | + {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, | |
1575 | + {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, | |
1576 | + {OPT_FSTR, "O", 0, "Ignored. (Placeholder for '-O' compiler options.)"}, | |
1577 | + {OPT_FLAG, "p", (char*)&showPrecedenceConflict, | |
1578 | + "Show conflicts resolved by precedence rules"}, | |
1426 | 1579 | {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, |
1580 | + {OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"}, | |
1427 | 1581 | {OPT_FLAG, "s", (char*)&statistics, |
1428 | 1582 | "Print parser stats to standard output."}, |
1429 | 1583 | {OPT_FLAG, "x", (char*)&version, "Print the version number."}, |
1584 | + {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, | |
1585 | + {OPT_FSTR, "W", 0, "Ignored. (Placeholder for '-W' compiler options.)"}, | |
1430 | 1586 | {OPT_FLAG,0,0,0} |
1431 | 1587 | }; |
1432 | 1588 | int i; |
1433 | 1589 | struct lemon lem; |
1590 | + struct rule *rp; | |
1434 | 1591 | |
1435 | 1592 | OptInit(argv,options,stderr); |
1436 | 1593 | if( version ){ |
@@ -1450,7 +1607,9 @@ | ||
1450 | 1607 | State_init(); |
1451 | 1608 | lem.argv0 = argv[0]; |
1452 | 1609 | lem.filename = OptArg(0); |
1610 | + lem.outbasefilename = stitch_outdir(lem.filename); | |
1453 | 1611 | lem.basisflag = basisflag; |
1612 | + lem.nolinenosflag = nolinenosflag; | |
1454 | 1613 | Symbol_new("$"); |
1455 | 1614 | lem.errsym = Symbol_new("error"); |
1456 | 1615 | lem.errsym->useCnt = 0; |
@@ -1464,16 +1623,31 @@ | ||
1464 | 1623 | } |
1465 | 1624 | |
1466 | 1625 | /* Count and index the symbols of the grammar */ |
1626 | + Symbol_new("{default}"); | |
1467 | 1627 | lem.nsymbol = Symbol_count(); |
1468 | - Symbol_new("{default}"); | |
1469 | 1628 | lem.symbols = Symbol_arrayof(); |
1470 | - for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; | |
1471 | - qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*), | |
1472 | - (int(*)(const void*, const void*))Symbolcmpp); | |
1473 | - for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; | |
1474 | - for(i=1; isupper(lem.symbols[i]->name[0]); i++); | |
1629 | + for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; | |
1630 | + qsort(lem.symbols,lem.nsymbol,sizeof(struct symbol*), Symbolcmpp); | |
1631 | + for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; | |
1632 | + while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; } | |
1633 | + assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 ); | |
1634 | + lem.nsymbol = i - 1; | |
1635 | + for(i=1; ISUPPER(lem.symbols[i]->name[0]); i++); | |
1475 | 1636 | lem.nterminal = i; |
1476 | 1637 | |
1638 | + /* Assign sequential rule numbers. Start with 0. Put rules that have no | |
1639 | + ** reduce action C-code associated with them last, so that the switch() | |
1640 | + ** statement that selects reduction actions will have a smaller jump table. | |
1641 | + */ | |
1642 | + for(i=0, rp=lem.rule; rp; rp=rp->next){ | |
1643 | + rp->iRule = rp->code ? i++ : -1; | |
1644 | + } | |
1645 | + for(rp=lem.rule; rp; rp=rp->next){ | |
1646 | + if( rp->iRule<0 ) rp->iRule = i++; | |
1647 | + } | |
1648 | + lem.startRule = lem.rule; | |
1649 | + lem.rule = Rule_sort(lem.rule); | |
1650 | + | |
1477 | 1651 | /* Generate a reprint of the grammar, if requested on the command line */ |
1478 | 1652 | if( rpflag ){ |
1479 | 1653 | Reprint(&lem); |
@@ -1507,8 +1681,9 @@ | ||
1507 | 1681 | if( compress==0 ) CompressTables(&lem); |
1508 | 1682 | |
1509 | 1683 | /* Reorder and renumber the states so that states with fewer choices |
1510 | - ** occur at the end. */ | |
1511 | - ResortStates(&lem); | |
1684 | + ** occur at the end. This is an optimization that helps make the | |
1685 | + ** generated parser tables smaller. */ | |
1686 | + if( noResort==0 ) ResortStates(&lem); | |
1512 | 1687 | |
1513 | 1688 | /* Generate a report of the parser generated. (the "y.output" file) */ |
1514 | 1689 | if( !quiet ) ReportOutput(&lem); |
@@ -1522,10 +1697,15 @@ | ||
1522 | 1697 | if( !mhflag ) ReportHeader(&lem); |
1523 | 1698 | } |
1524 | 1699 | if( statistics ){ |
1525 | - printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", | |
1526 | - lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); | |
1527 | - printf(" %d states, %d parser table entries, %d conflicts\n", | |
1528 | - lem.nstate, lem.tablesize, lem.nconflict); | |
1700 | + printf("Parser statistics:\n"); | |
1701 | + stats_line("terminal symbols", lem.nterminal); | |
1702 | + stats_line("non-terminal symbols", lem.nsymbol - lem.nterminal); | |
1703 | + stats_line("total symbols", lem.nsymbol); | |
1704 | + stats_line("rules", lem.nrule); | |
1705 | + stats_line("states", lem.nxstate); | |
1706 | + stats_line("conflicts", lem.nconflict); | |
1707 | + stats_line("action table entries", lem.nactiontab); | |
1708 | + stats_line("total table size (bytes)", lem.tablesize); | |
1529 | 1709 | } |
1530 | 1710 | if( lem.nconflict ){ |
1531 | 1711 | fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); |
@@ -1586,7 +1766,7 @@ | ||
1586 | 1766 | }else if( b==0 ){ |
1587 | 1767 | head = a; |
1588 | 1768 | }else{ |
1589 | - if( (*cmp)(a,b)<0 ){ | |
1769 | + if( (*cmp)(a,b)<=0 ){ | |
1590 | 1770 | ptr = a; |
1591 | 1771 | a = NEXT(a); |
1592 | 1772 | }else{ |
@@ -1595,7 +1775,7 @@ | ||
1595 | 1775 | } |
1596 | 1776 | head = ptr; |
1597 | 1777 | while( a && b ){ |
1598 | - if( (*cmp)(a,b)<0 ){ | |
1778 | + if( (*cmp)(a,b)<=0 ){ | |
1599 | 1779 | NEXT(ptr) = a; |
1600 | 1780 | ptr = a; |
1601 | 1781 | a = NEXT(a); |
@@ -1644,7 +1824,7 @@ | ||
1644 | 1824 | set[i] = ep; |
1645 | 1825 | } |
1646 | 1826 | ep = 0; |
1647 | - for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(ep,set[i],cmp,offset); | |
1827 | + for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(set[i],ep,cmp,offset); | |
1648 | 1828 | return ep; |
1649 | 1829 | } |
1650 | 1830 | /************************ From the file "option.c" **************************/ |
@@ -1658,18 +1838,15 @@ | ||
1658 | 1838 | ** Print the command line with a carrot pointing to the k-th character |
1659 | 1839 | ** of the n-th field. |
1660 | 1840 | */ |
1661 | -static void errline(n,k,err) | |
1662 | -int n; | |
1663 | -int k; | |
1664 | -FILE *err; | |
1841 | +static void errline(int n, int k, FILE *err) | |
1665 | 1842 | { |
1666 | 1843 | int i; |
1667 | 1844 | size_t spcnt; |
1668 | 1845 | if( argv[0] ) fprintf(err,"%s",argv[0]); |
1669 | - spcnt = strlen(argv[0]) + 1; | |
1846 | + spcnt = lemonStrlen(argv[0]) + 1; | |
1670 | 1847 | for(i=1; i<n && argv[i]; i++){ |
1671 | 1848 | fprintf(err," %s",argv[i]); |
1672 | - spcnt += strlen(argv[i])+1; | |
1849 | + spcnt += lemonStrlen(argv[i])+1; | |
1673 | 1850 | } |
1674 | 1851 | spcnt += k; |
1675 | 1852 | for(; argv[i]; i++) fprintf(err," %s",argv[i]); |
@@ -1684,8 +1861,7 @@ | ||
1684 | 1861 | ** Return the index of the N-th non-switch argument. Return -1 |
1685 | 1862 | ** if N is out of range. |
1686 | 1863 | */ |
1687 | -static int argindex(n) | |
1688 | -int n; | |
1864 | +static int argindex(int n) | |
1689 | 1865 | { |
1690 | 1866 | int i; |
1691 | 1867 | int dashdash = 0; |
@@ -1706,15 +1882,13 @@ | ||
1706 | 1882 | /* |
1707 | 1883 | ** Process a flag command line argument. |
1708 | 1884 | */ |
1709 | -static int handleflags(i,err) | |
1710 | -int i; | |
1711 | -FILE *err; | |
1885 | +static int handleflags(int i, FILE *err) | |
1712 | 1886 | { |
1713 | 1887 | int v; |
1714 | 1888 | int errcnt = 0; |
1715 | 1889 | int j; |
1716 | 1890 | for(j=0; op[j].label; j++){ |
1717 | - if( strncmp(&argv[i][1],op[j].label,strlen(op[j].label))==0 ) break; | |
1891 | + if( strncmp(&argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break; | |
1718 | 1892 | } |
1719 | 1893 | v = argv[i][0]=='-' ? 1 : 0; |
1720 | 1894 | if( op[j].label==0 ){ |
@@ -1723,12 +1897,14 @@ | ||
1723 | 1897 | errline(i,1,err); |
1724 | 1898 | } |
1725 | 1899 | errcnt++; |
1900 | + }else if( op[j].arg==0 ){ | |
1901 | + /* Ignore this option */ | |
1726 | 1902 | }else if( op[j].type==OPT_FLAG ){ |
1727 | 1903 | *((int*)op[j].arg) = v; |
1728 | 1904 | }else if( op[j].type==OPT_FFLAG ){ |
1729 | - (*(void(*)())(op[j].arg))(v); | |
1905 | + (*(void(*)(int))(op[j].arg))(v); | |
1730 | 1906 | }else if( op[j].type==OPT_FSTR ){ |
1731 | - (*(void(*)())(op[j].arg))(&argv[i][2]); | |
1907 | + (*(void(*)(char *))(op[j].arg))(&argv[i][2]); | |
1732 | 1908 | }else{ |
1733 | 1909 | if( err ){ |
1734 | 1910 | fprintf(err,"%smissing argument on switch.\n",emsg); |
@@ -1742,9 +1918,7 @@ | ||
1742 | 1918 | /* |
1743 | 1919 | ** Process a command line switch which has an argument. |
1744 | 1920 | */ |
1745 | -static int handleswitch(i,err) | |
1746 | -int i; | |
1747 | -FILE *err; | |
1921 | +static int handleswitch(int i, FILE *err) | |
1748 | 1922 | { |
1749 | 1923 | int lv = 0; |
1750 | 1924 | double dv = 0.0; |
@@ -1781,7 +1955,8 @@ | ||
1781 | 1955 | dv = strtod(cp,&end); |
1782 | 1956 | if( *end ){ |
1783 | 1957 | if( err ){ |
1784 | - fprintf(err,"%sillegal character in floating-point argument.\n",emsg); | |
1958 | + fprintf(err, | |
1959 | + "%sillegal character in floating-point argument.\n",emsg); | |
1785 | 1960 | errline(i,((size_t)end)-(size_t)argv[i],err); |
1786 | 1961 | } |
1787 | 1962 | errcnt++; |
@@ -1811,29 +1986,26 @@ | ||
1811 | 1986 | *(double*)(op[j].arg) = dv; |
1812 | 1987 | break; |
1813 | 1988 | case OPT_FDBL: |
1814 | - (*(void(*)())(op[j].arg))(dv); | |
1989 | + (*(void(*)(double))(op[j].arg))(dv); | |
1815 | 1990 | break; |
1816 | 1991 | case OPT_INT: |
1817 | 1992 | *(int*)(op[j].arg) = lv; |
1818 | 1993 | break; |
1819 | 1994 | case OPT_FINT: |
1820 | - (*(void(*)())(op[j].arg))((int)lv); | |
1995 | + (*(void(*)(int))(op[j].arg))((int)lv); | |
1821 | 1996 | break; |
1822 | 1997 | case OPT_STR: |
1823 | 1998 | *(char**)(op[j].arg) = sv; |
1824 | 1999 | break; |
1825 | 2000 | case OPT_FSTR: |
1826 | - (*(void(*)())(op[j].arg))(sv); | |
2001 | + (*(void(*)(char *))(op[j].arg))(sv); | |
1827 | 2002 | break; |
1828 | 2003 | } |
1829 | 2004 | } |
1830 | 2005 | return errcnt; |
1831 | 2006 | } |
1832 | 2007 | |
1833 | -int OptInit(a,o,err) | |
1834 | -char **a; | |
1835 | -struct s_options *o; | |
1836 | -FILE *err; | |
2008 | +int OptInit(char **a, struct s_options *o, FILE *err) | |
1837 | 2009 | { |
1838 | 2010 | int errcnt = 0; |
1839 | 2011 | argv = a; |
@@ -1870,16 +2042,14 @@ | ||
1870 | 2042 | return cnt; |
1871 | 2043 | } |
1872 | 2044 | |
1873 | -char *OptArg(n) | |
1874 | -int n; | |
2045 | +char *OptArg(int n) | |
1875 | 2046 | { |
1876 | 2047 | int i; |
1877 | 2048 | i = argindex(n); |
1878 | 2049 | return i>=0 ? argv[i] : 0; |
1879 | 2050 | } |
1880 | 2051 | |
1881 | -void OptErr(n) | |
1882 | -int n; | |
2052 | +void OptErr(int n) | |
1883 | 2053 | { |
1884 | 2054 | int i; |
1885 | 2055 | i = argindex(n); |
@@ -1891,7 +2061,7 @@ | ||
1891 | 2061 | size_t max, len; |
1892 | 2062 | max = 0; |
1893 | 2063 | for(i=0; op[i].label; i++){ |
1894 | - len = strlen(op[i].label) + 1; | |
2064 | + len = lemonStrlen(op[i].label) + 1; | |
1895 | 2065 | switch( op[i].type ){ |
1896 | 2066 | case OPT_FLAG: |
1897 | 2067 | case OPT_FFLAG: |
@@ -1919,18 +2089,18 @@ | ||
1919 | 2089 | break; |
1920 | 2090 | case OPT_INT: |
1921 | 2091 | case OPT_FINT: |
1922 | - fprintf(errstream," %s=<integer>%*s %s\n",op[i].label, | |
1923 | - (int)(max-strlen(op[i].label)-9),"",op[i].message); | |
2092 | + fprintf(errstream," -%s<integer>%*s %s\n",op[i].label, | |
2093 | + (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); | |
1924 | 2094 | break; |
1925 | 2095 | case OPT_DBL: |
1926 | 2096 | case OPT_FDBL: |
1927 | - fprintf(errstream," %s=<real>%*s %s\n",op[i].label, | |
1928 | - (int)(max-strlen(op[i].label)-6),"",op[i].message); | |
2097 | + fprintf(errstream," -%s<real>%*s %s\n",op[i].label, | |
2098 | + (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); | |
1929 | 2099 | break; |
1930 | 2100 | case OPT_STR: |
1931 | 2101 | case OPT_FSTR: |
1932 | - fprintf(errstream," %s=<string>%*s %s\n",op[i].label, | |
1933 | - (int)(max-strlen(op[i].label)-8),"",op[i].message); | |
2102 | + fprintf(errstream," -%s<string>%*s %s\n",op[i].label, | |
2103 | + (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); | |
1934 | 2104 | break; |
1935 | 2105 | } |
1936 | 2106 | } |
@@ -1941,44 +2111,49 @@ | ||
1941 | 2111 | */ |
1942 | 2112 | |
1943 | 2113 | /* The state of the parser */ |
2114 | +enum e_state { | |
2115 | + INITIALIZE, | |
2116 | + WAITING_FOR_DECL_OR_RULE, | |
2117 | + WAITING_FOR_DECL_KEYWORD, | |
2118 | + WAITING_FOR_DECL_ARG, | |
2119 | + WAITING_FOR_PRECEDENCE_SYMBOL, | |
2120 | + WAITING_FOR_ARROW, | |
2121 | + IN_RHS, | |
2122 | + LHS_ALIAS_1, | |
2123 | + LHS_ALIAS_2, | |
2124 | + LHS_ALIAS_3, | |
2125 | + RHS_ALIAS_1, | |
2126 | + RHS_ALIAS_2, | |
2127 | + PRECEDENCE_MARK_1, | |
2128 | + PRECEDENCE_MARK_2, | |
2129 | + RESYNC_AFTER_RULE_ERROR, | |
2130 | + RESYNC_AFTER_DECL_ERROR, | |
2131 | + WAITING_FOR_DESTRUCTOR_SYMBOL, | |
2132 | + WAITING_FOR_DATATYPE_SYMBOL, | |
2133 | + WAITING_FOR_FALLBACK_ID, | |
2134 | + WAITING_FOR_WILDCARD_ID, | |
2135 | + WAITING_FOR_CLASS_ID, | |
2136 | + WAITING_FOR_CLASS_TOKEN | |
2137 | +}; | |
1944 | 2138 | struct pstate { |
1945 | 2139 | char *filename; /* Name of the input file */ |
1946 | 2140 | int tokenlineno; /* Linenumber at which current token starts */ |
1947 | 2141 | int errorcnt; /* Number of errors so far */ |
1948 | 2142 | char *tokenstart; /* Text of current token */ |
1949 | 2143 | struct lemon *gp; /* Global state vector */ |
1950 | - enum e_state { | |
1951 | - INITIALIZE, | |
1952 | - WAITING_FOR_DECL_OR_RULE, | |
1953 | - WAITING_FOR_DECL_KEYWORD, | |
1954 | - WAITING_FOR_DECL_ARG, | |
1955 | - WAITING_FOR_PRECEDENCE_SYMBOL, | |
1956 | - WAITING_FOR_ARROW, | |
1957 | - IN_RHS, | |
1958 | - LHS_ALIAS_1, | |
1959 | - LHS_ALIAS_2, | |
1960 | - LHS_ALIAS_3, | |
1961 | - RHS_ALIAS_1, | |
1962 | - RHS_ALIAS_2, | |
1963 | - PRECEDENCE_MARK_1, | |
1964 | - PRECEDENCE_MARK_2, | |
1965 | - RESYNC_AFTER_RULE_ERROR, | |
1966 | - RESYNC_AFTER_DECL_ERROR, | |
1967 | - WAITING_FOR_DESTRUCTOR_SYMBOL, | |
1968 | - WAITING_FOR_DATATYPE_SYMBOL, | |
1969 | - WAITING_FOR_FALLBACK_ID, | |
1970 | - WAITING_FOR_WILDCARD_ID | |
1971 | - } state; /* The state of the parser */ | |
2144 | + enum e_state state; /* The state of the parser */ | |
1972 | 2145 | struct symbol *fallback; /* The fallback token */ |
2146 | + struct symbol *tkclass; /* Token class symbol */ | |
1973 | 2147 | struct symbol *lhs; /* Left-hand side of current rule */ |
1974 | - char *lhsalias; /* Alias for the LHS */ | |
2148 | + const char *lhsalias; /* Alias for the LHS */ | |
1975 | 2149 | int nrhs; /* Number of right-hand side symbols seen */ |
1976 | 2150 | struct symbol *rhs[MAXRHS]; /* RHS symbols */ |
1977 | - char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */ | |
2151 | + const char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */ | |
1978 | 2152 | struct rule *prevrule; /* Previous rule parsed */ |
1979 | - char *declkeyword; /* Keyword of a declaration */ | |
2153 | + const char *declkeyword; /* Keyword of a declaration */ | |
1980 | 2154 | char **declargslot; /* Where the declaration argument should be put */ |
1981 | - int *decllnslot; /* Where the declaration linenumber is put */ | |
2155 | + int insertLineMacro; /* Add #line before declaration insert */ | |
2156 | + int *decllinenoslot; /* Where to write declaration line number */ | |
1982 | 2157 | enum e_assoc declassoc; /* Assign this association to decl arguments */ |
1983 | 2158 | int preccounter; /* Assign this precedence to decl arguments */ |
1984 | 2159 | struct rule *firstrule; /* Pointer to first rule in the grammar */ |
@@ -1986,10 +2161,9 @@ | ||
1986 | 2161 | }; |
1987 | 2162 | |
1988 | 2163 | /* Parse a single token */ |
1989 | -static void parseonetoken(psp) | |
1990 | -struct pstate *psp; | |
2164 | +static void parseonetoken(struct pstate *psp) | |
1991 | 2165 | { |
1992 | - char *x; | |
2166 | + const char *x; | |
1993 | 2167 | x = Strsafe(psp->tokenstart); /* Save the token permanently */ |
1994 | 2168 | #if 0 |
1995 | 2169 | printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno, |
@@ -2005,7 +2179,7 @@ | ||
2005 | 2179 | case WAITING_FOR_DECL_OR_RULE: |
2006 | 2180 | if( x[0]=='%' ){ |
2007 | 2181 | psp->state = WAITING_FOR_DECL_KEYWORD; |
2008 | - }else if( islower(x[0]) ){ | |
2182 | + }else if( ISLOWER(x[0]) ){ | |
2009 | 2183 | psp->lhs = Symbol_new(x); |
2010 | 2184 | psp->nrhs = 0; |
2011 | 2185 | psp->lhsalias = 0; |
@@ -2013,10 +2187,10 @@ | ||
2013 | 2187 | }else if( x[0]=='{' ){ |
2014 | 2188 | if( psp->prevrule==0 ){ |
2015 | 2189 | ErrorMsg(psp->filename,psp->tokenlineno, |
2016 | -"There is not prior rule opon which to attach the code \ | |
2190 | +"There is no prior rule upon which to attach the code \ | |
2017 | 2191 | fragment which begins on this line."); |
2018 | 2192 | psp->errorcnt++; |
2019 | - }else if( psp->prevrule->code!=0 ){ | |
2193 | + }else if( psp->prevrule->code!=0 ){ | |
2020 | 2194 | ErrorMsg(psp->filename,psp->tokenlineno, |
2021 | 2195 | "Code fragment beginning on this line is not the first \ |
2022 | 2196 | to follow the previous rule."); |
@@ -2024,7 +2198,8 @@ | ||
2024 | 2198 | }else{ |
2025 | 2199 | psp->prevrule->line = psp->tokenlineno; |
2026 | 2200 | psp->prevrule->code = &x[1]; |
2027 | - } | |
2201 | + psp->prevrule->noCode = 0; | |
2202 | + } | |
2028 | 2203 | }else if( x[0]=='[' ){ |
2029 | 2204 | psp->state = PRECEDENCE_MARK_1; |
2030 | 2205 | }else{ |
@@ -2035,7 +2210,7 @@ | ||
2035 | 2210 | } |
2036 | 2211 | break; |
2037 | 2212 | case PRECEDENCE_MARK_1: |
2038 | - if( !isupper(x[0]) ){ | |
2213 | + if( !ISUPPER(x[0]) ){ | |
2039 | 2214 | ErrorMsg(psp->filename,psp->tokenlineno, |
2040 | 2215 | "The precedence symbol must be a terminal."); |
2041 | 2216 | psp->errorcnt++; |
@@ -2075,7 +2250,7 @@ | ||
2075 | 2250 | } |
2076 | 2251 | break; |
2077 | 2252 | case LHS_ALIAS_1: |
2078 | - if( isalpha(x[0]) ){ | |
2253 | + if( ISALPHA(x[0]) ){ | |
2079 | 2254 | psp->lhsalias = x; |
2080 | 2255 | psp->state = LHS_ALIAS_2; |
2081 | 2256 | }else{ |
@@ -2121,7 +2296,7 @@ | ||
2121 | 2296 | int i; |
2122 | 2297 | rp->ruleline = psp->tokenlineno; |
2123 | 2298 | rp->rhs = (struct symbol**)&rp[1]; |
2124 | - rp->rhsalias = (char**)&(rp->rhs[psp->nrhs]); | |
2299 | + rp->rhsalias = (const char**)&(rp->rhs[psp->nrhs]); | |
2125 | 2300 | for(i=0; i<psp->nrhs; i++){ |
2126 | 2301 | rp->rhs[i] = psp->rhs[i]; |
2127 | 2302 | rp->rhsalias[i] = psp->alias[i]; |
@@ -2130,6 +2305,7 @@ | ||
2130 | 2305 | rp->lhsalias = psp->lhsalias; |
2131 | 2306 | rp->nrhs = psp->nrhs; |
2132 | 2307 | rp->code = 0; |
2308 | + rp->noCode = 1; | |
2133 | 2309 | rp->precsym = 0; |
2134 | 2310 | rp->index = psp->gp->nrule++; |
2135 | 2311 | rp->nextlhs = rp->lhs->rule; |
@@ -2140,11 +2316,11 @@ | ||
2140 | 2316 | }else{ |
2141 | 2317 | psp->lastrule->next = rp; |
2142 | 2318 | psp->lastrule = rp; |
2143 | - } | |
2319 | + } | |
2144 | 2320 | psp->prevrule = rp; |
2145 | - } | |
2321 | + } | |
2146 | 2322 | psp->state = WAITING_FOR_DECL_OR_RULE; |
2147 | - }else if( isalpha(x[0]) ){ | |
2323 | + }else if( ISALPHA(x[0]) ){ | |
2148 | 2324 | if( psp->nrhs>=MAXRHS ){ |
2149 | 2325 | ErrorMsg(psp->filename,psp->tokenlineno, |
2150 | 2326 | "Too many symbols on RHS of rule beginning at \"%s\".", |
@@ -2160,18 +2336,19 @@ | ||
2160 | 2336 | struct symbol *msp = psp->rhs[psp->nrhs-1]; |
2161 | 2337 | if( msp->type!=MULTITERMINAL ){ |
2162 | 2338 | struct symbol *origsp = msp; |
2163 | - msp = calloc(1,sizeof(*msp)); | |
2339 | + msp = (struct symbol *) calloc(1,sizeof(*msp)); | |
2164 | 2340 | msp->type = MULTITERMINAL; |
2165 | 2341 | msp->nsubsym = 1; |
2166 | - msp->subsym = calloc(1,sizeof(struct symbol*)); | |
2342 | + msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*)); | |
2167 | 2343 | msp->subsym[0] = origsp; |
2168 | 2344 | msp->name = origsp->name; |
2169 | 2345 | psp->rhs[psp->nrhs-1] = msp; |
2170 | 2346 | } |
2171 | 2347 | msp->nsubsym++; |
2172 | - msp->subsym = realloc(msp->subsym, sizeof(struct symbol*)*msp->nsubsym); | |
2348 | + msp->subsym = (struct symbol **) realloc(msp->subsym, | |
2349 | + sizeof(struct symbol*)*msp->nsubsym); | |
2173 | 2350 | msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]); |
2174 | - if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){ | |
2351 | + if( ISLOWER(x[1]) || ISLOWER(msp->subsym[0]->name[0]) ){ | |
2175 | 2352 | ErrorMsg(psp->filename,psp->tokenlineno, |
2176 | 2353 | "Cannot form a compound containing a non-terminal"); |
2177 | 2354 | psp->errorcnt++; |
@@ -2186,7 +2363,7 @@ | ||
2186 | 2363 | } |
2187 | 2364 | break; |
2188 | 2365 | case RHS_ALIAS_1: |
2189 | - if( isalpha(x[0]) ){ | |
2366 | + if( ISALPHA(x[0]) ){ | |
2190 | 2367 | psp->alias[psp->nrhs-1] = x; |
2191 | 2368 | psp->state = RHS_ALIAS_2; |
2192 | 2369 | }else{ |
@@ -2208,49 +2385,49 @@ | ||
2208 | 2385 | } |
2209 | 2386 | break; |
2210 | 2387 | case WAITING_FOR_DECL_KEYWORD: |
2211 | - if( isalpha(x[0]) ){ | |
2388 | + if( ISALPHA(x[0]) ){ | |
2212 | 2389 | psp->declkeyword = x; |
2213 | 2390 | psp->declargslot = 0; |
2214 | - psp->decllnslot = 0; | |
2391 | + psp->decllinenoslot = 0; | |
2392 | + psp->insertLineMacro = 1; | |
2215 | 2393 | psp->state = WAITING_FOR_DECL_ARG; |
2216 | 2394 | if( strcmp(x,"name")==0 ){ |
2217 | 2395 | psp->declargslot = &(psp->gp->name); |
2396 | + psp->insertLineMacro = 0; | |
2218 | 2397 | }else if( strcmp(x,"include")==0 ){ |
2219 | 2398 | psp->declargslot = &(psp->gp->include); |
2220 | - psp->decllnslot = &psp->gp->includeln; | |
2221 | 2399 | }else if( strcmp(x,"code")==0 ){ |
2222 | 2400 | psp->declargslot = &(psp->gp->extracode); |
2223 | - psp->decllnslot = &psp->gp->extracodeln; | |
2224 | 2401 | }else if( strcmp(x,"token_destructor")==0 ){ |
2225 | 2402 | psp->declargslot = &psp->gp->tokendest; |
2226 | - psp->decllnslot = &psp->gp->tokendestln; | |
2227 | 2403 | }else if( strcmp(x,"default_destructor")==0 ){ |
2228 | 2404 | psp->declargslot = &psp->gp->vardest; |
2229 | - psp->decllnslot = &psp->gp->vardestln; | |
2230 | 2405 | }else if( strcmp(x,"token_prefix")==0 ){ |
2231 | 2406 | psp->declargslot = &psp->gp->tokenprefix; |
2407 | + psp->insertLineMacro = 0; | |
2232 | 2408 | }else if( strcmp(x,"syntax_error")==0 ){ |
2233 | 2409 | psp->declargslot = &(psp->gp->error); |
2234 | - psp->decllnslot = &psp->gp->errorln; | |
2235 | 2410 | }else if( strcmp(x,"parse_accept")==0 ){ |
2236 | 2411 | psp->declargslot = &(psp->gp->accept); |
2237 | - psp->decllnslot = &psp->gp->acceptln; | |
2238 | 2412 | }else if( strcmp(x,"parse_failure")==0 ){ |
2239 | 2413 | psp->declargslot = &(psp->gp->failure); |
2240 | - psp->decllnslot = &psp->gp->failureln; | |
2241 | 2414 | }else if( strcmp(x,"stack_overflow")==0 ){ |
2242 | 2415 | psp->declargslot = &(psp->gp->overflow); |
2243 | - psp->decllnslot = &psp->gp->overflowln; | |
2244 | 2416 | }else if( strcmp(x,"extra_argument")==0 ){ |
2245 | 2417 | psp->declargslot = &(psp->gp->arg); |
2418 | + psp->insertLineMacro = 0; | |
2246 | 2419 | }else if( strcmp(x,"token_type")==0 ){ |
2247 | 2420 | psp->declargslot = &(psp->gp->tokentype); |
2421 | + psp->insertLineMacro = 0; | |
2248 | 2422 | }else if( strcmp(x,"default_type")==0 ){ |
2249 | 2423 | psp->declargslot = &(psp->gp->vartype); |
2424 | + psp->insertLineMacro = 0; | |
2250 | 2425 | }else if( strcmp(x,"stack_size")==0 ){ |
2251 | 2426 | psp->declargslot = &(psp->gp->stacksize); |
2427 | + psp->insertLineMacro = 0; | |
2252 | 2428 | }else if( strcmp(x,"start_symbol")==0 ){ |
2253 | 2429 | psp->declargslot = &(psp->gp->start); |
2430 | + psp->insertLineMacro = 0; | |
2254 | 2431 | }else if( strcmp(x,"left")==0 ){ |
2255 | 2432 | psp->preccounter++; |
2256 | 2433 | psp->declassoc = LEFT; |
@@ -2272,6 +2449,8 @@ | ||
2272 | 2449 | psp->state = WAITING_FOR_FALLBACK_ID; |
2273 | 2450 | }else if( strcmp(x,"wildcard")==0 ){ |
2274 | 2451 | psp->state = WAITING_FOR_WILDCARD_ID; |
2452 | + }else if( strcmp(x,"token_class")==0 ){ | |
2453 | + psp->state = WAITING_FOR_CLASS_ID; | |
2275 | 2454 | }else{ |
2276 | 2455 | ErrorMsg(psp->filename,psp->tokenlineno, |
2277 | 2456 | "Unknown declaration keyword: \"%%%s\".",x); |
@@ -2286,7 +2465,7 @@ | ||
2286 | 2465 | } |
2287 | 2466 | break; |
2288 | 2467 | case WAITING_FOR_DESTRUCTOR_SYMBOL: |
2289 | - if( !isalpha(x[0]) ){ | |
2468 | + if( !ISALPHA(x[0]) ){ | |
2290 | 2469 | ErrorMsg(psp->filename,psp->tokenlineno, |
2291 | 2470 | "Symbol name missing after %%destructor keyword"); |
2292 | 2471 | psp->errorcnt++; |
@@ -2294,27 +2473,38 @@ | ||
2294 | 2473 | }else{ |
2295 | 2474 | struct symbol *sp = Symbol_new(x); |
2296 | 2475 | psp->declargslot = &sp->destructor; |
2297 | - psp->decllnslot = &sp->destructorln; | |
2476 | + psp->decllinenoslot = &sp->destLineno; | |
2477 | + psp->insertLineMacro = 1; | |
2298 | 2478 | psp->state = WAITING_FOR_DECL_ARG; |
2299 | 2479 | } |
2300 | 2480 | break; |
2301 | 2481 | case WAITING_FOR_DATATYPE_SYMBOL: |
2302 | - if( !isalpha(x[0]) ){ | |
2482 | + if( !ISALPHA(x[0]) ){ | |
2303 | 2483 | ErrorMsg(psp->filename,psp->tokenlineno, |
2304 | - "Symbol name missing after %%destructor keyword"); | |
2484 | + "Symbol name missing after %%type keyword"); | |
2305 | 2485 | psp->errorcnt++; |
2306 | 2486 | psp->state = RESYNC_AFTER_DECL_ERROR; |
2307 | 2487 | }else{ |
2308 | - struct symbol *sp = Symbol_new(x); | |
2309 | - psp->declargslot = &sp->datatype; | |
2310 | - psp->decllnslot = 0; | |
2311 | - psp->state = WAITING_FOR_DECL_ARG; | |
2488 | + struct symbol *sp = Symbol_find(x); | |
2489 | + if((sp) && (sp->datatype)){ | |
2490 | + ErrorMsg(psp->filename,psp->tokenlineno, | |
2491 | + "Symbol %%type \"%s\" already defined", x); | |
2492 | + psp->errorcnt++; | |
2493 | + psp->state = RESYNC_AFTER_DECL_ERROR; | |
2494 | + }else{ | |
2495 | + if (!sp){ | |
2496 | + sp = Symbol_new(x); | |
2497 | + } | |
2498 | + psp->declargslot = &sp->datatype; | |
2499 | + psp->insertLineMacro = 0; | |
2500 | + psp->state = WAITING_FOR_DECL_ARG; | |
2501 | + } | |
2312 | 2502 | } |
2313 | 2503 | break; |
2314 | 2504 | case WAITING_FOR_PRECEDENCE_SYMBOL: |
2315 | 2505 | if( x[0]=='.' ){ |
2316 | 2506 | psp->state = WAITING_FOR_DECL_OR_RULE; |
2317 | - }else if( isupper(x[0]) ){ | |
2507 | + }else if( ISUPPER(x[0]) ){ | |
2318 | 2508 | struct symbol *sp; |
2319 | 2509 | sp = Symbol_new(x); |
2320 | 2510 | if( sp->prec>=0 ){ |
@@ -2332,18 +2522,57 @@ | ||
2332 | 2522 | } |
2333 | 2523 | break; |
2334 | 2524 | case WAITING_FOR_DECL_ARG: |
2335 | - if( (x[0]=='{' || x[0]=='\"' || isalnum(x[0])) ){ | |
2336 | - if( *(psp->declargslot)!=0 ){ | |
2337 | - ErrorMsg(psp->filename,psp->tokenlineno, | |
2338 | - "The argument \"%s\" to declaration \"%%%s\" is not the first.", | |
2339 | - x[0]=='\"' ? &x[1] : x,psp->declkeyword); | |
2340 | - psp->errorcnt++; | |
2341 | - psp->state = RESYNC_AFTER_DECL_ERROR; | |
2342 | - }else{ | |
2343 | - *(psp->declargslot) = (x[0]=='\"' || x[0]=='{') ? &x[1] : x; | |
2344 | - if( psp->decllnslot ) *psp->decllnslot = psp->tokenlineno; | |
2345 | - psp->state = WAITING_FOR_DECL_OR_RULE; | |
2346 | - } | |
2525 | + if( x[0]=='{' || x[0]=='\"' || ISALNUM(x[0]) ){ | |
2526 | + const char *zOld, *zNew; | |
2527 | + char *zBuf, *z; | |
2528 | + int nOld, n, nLine, nNew, nBack; | |
2529 | + int addLineMacro; | |
2530 | + char zLine[50]; | |
2531 | + zNew = x; | |
2532 | + if( zNew[0]=='"' || zNew[0]=='{' ) zNew++; | |
2533 | + nNew = lemonStrlen(zNew); | |
2534 | + if( *psp->declargslot ){ | |
2535 | + zOld = *psp->declargslot; | |
2536 | + }else{ | |
2537 | + zOld = ""; | |
2538 | + } | |
2539 | + nOld = lemonStrlen(zOld); | |
2540 | + n = nOld + nNew + 20; | |
2541 | + addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && | |
2542 | + (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); | |
2543 | + if( addLineMacro ){ | |
2544 | + for(z=psp->filename, nBack=0; *z; z++){ | |
2545 | + if( *z=='\\' ) nBack++; | |
2546 | + } | |
2547 | + sprintf(zLine, "#line %d ", psp->tokenlineno); | |
2548 | + nLine = lemonStrlen(zLine); | |
2549 | + n += nLine + lemonStrlen(psp->filename) + nBack; | |
2550 | + } | |
2551 | + *psp->declargslot = (char *) realloc(*psp->declargslot, n); | |
2552 | + zBuf = *psp->declargslot + nOld; | |
2553 | + if( addLineMacro ){ | |
2554 | + if( nOld && zBuf[-1]!='\n' ){ | |
2555 | + *(zBuf++) = '\n'; | |
2556 | + } | |
2557 | + memcpy(zBuf, zLine, nLine); | |
2558 | + zBuf += nLine; | |
2559 | + *(zBuf++) = '"'; | |
2560 | + for(z=psp->filename; *z; z++){ | |
2561 | + if( *z=='\\' ){ | |
2562 | + *(zBuf++) = '\\'; | |
2563 | + } | |
2564 | + *(zBuf++) = *z; | |
2565 | + } | |
2566 | + *(zBuf++) = '"'; | |
2567 | + *(zBuf++) = '\n'; | |
2568 | + } | |
2569 | + if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){ | |
2570 | + psp->decllinenoslot[0] = psp->tokenlineno; | |
2571 | + } | |
2572 | + memcpy(zBuf, zNew, nNew); | |
2573 | + zBuf += nNew; | |
2574 | + *zBuf = 0; | |
2575 | + psp->state = WAITING_FOR_DECL_OR_RULE; | |
2347 | 2576 | }else{ |
2348 | 2577 | ErrorMsg(psp->filename,psp->tokenlineno, |
2349 | 2578 | "Illegal argument to %%%s: %s",psp->declkeyword,x); |
@@ -2354,7 +2583,7 @@ | ||
2354 | 2583 | case WAITING_FOR_FALLBACK_ID: |
2355 | 2584 | if( x[0]=='.' ){ |
2356 | 2585 | psp->state = WAITING_FOR_DECL_OR_RULE; |
2357 | - }else if( !isupper(x[0]) ){ | |
2586 | + }else if( !ISUPPER(x[0]) ){ | |
2358 | 2587 | ErrorMsg(psp->filename, psp->tokenlineno, |
2359 | 2588 | "%%fallback argument \"%s\" should be a token", x); |
2360 | 2589 | psp->errorcnt++; |
@@ -2375,7 +2604,7 @@ | ||
2375 | 2604 | case WAITING_FOR_WILDCARD_ID: |
2376 | 2605 | if( x[0]=='.' ){ |
2377 | 2606 | psp->state = WAITING_FOR_DECL_OR_RULE; |
2378 | - }else if( !isupper(x[0]) ){ | |
2607 | + }else if( !ISUPPER(x[0]) ){ | |
2379 | 2608 | ErrorMsg(psp->filename, psp->tokenlineno, |
2380 | 2609 | "%%wildcard argument \"%s\" should be a token", x); |
2381 | 2610 | psp->errorcnt++; |
@@ -2390,6 +2619,40 @@ | ||
2390 | 2619 | } |
2391 | 2620 | } |
2392 | 2621 | break; |
2622 | + case WAITING_FOR_CLASS_ID: | |
2623 | + if( !ISLOWER(x[0]) ){ | |
2624 | + ErrorMsg(psp->filename, psp->tokenlineno, | |
2625 | + "%%token_class must be followed by an identifier: ", x); | |
2626 | + psp->errorcnt++; | |
2627 | + psp->state = RESYNC_AFTER_DECL_ERROR; | |
2628 | + }else if( Symbol_find(x) ){ | |
2629 | + ErrorMsg(psp->filename, psp->tokenlineno, | |
2630 | + "Symbol \"%s\" already used", x); | |
2631 | + psp->errorcnt++; | |
2632 | + psp->state = RESYNC_AFTER_DECL_ERROR; | |
2633 | + }else{ | |
2634 | + psp->tkclass = Symbol_new(x); | |
2635 | + psp->tkclass->type = MULTITERMINAL; | |
2636 | + psp->state = WAITING_FOR_CLASS_TOKEN; | |
2637 | + } | |
2638 | + break; | |
2639 | + case WAITING_FOR_CLASS_TOKEN: | |
2640 | + if( x[0]=='.' ){ | |
2641 | + psp->state = WAITING_FOR_DECL_OR_RULE; | |
2642 | + }else if( ISUPPER(x[0]) || ((x[0]=='|' || x[0]=='/') && ISUPPER(x[1])) ){ | |
2643 | + struct symbol *msp = psp->tkclass; | |
2644 | + msp->nsubsym++; | |
2645 | + msp->subsym = (struct symbol **) realloc(msp->subsym, | |
2646 | + sizeof(struct symbol*)*msp->nsubsym); | |
2647 | + if( !ISUPPER(x[0]) ) x++; | |
2648 | + msp->subsym[msp->nsubsym-1] = Symbol_new(x); | |
2649 | + }else{ | |
2650 | + ErrorMsg(psp->filename, psp->tokenlineno, | |
2651 | + "%%token_class argument \"%s\" should be a token", x); | |
2652 | + psp->errorcnt++; | |
2653 | + psp->state = RESYNC_AFTER_DECL_ERROR; | |
2654 | + } | |
2655 | + break; | |
2393 | 2656 | case RESYNC_AFTER_RULE_ERROR: |
2394 | 2657 | /* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; |
2395 | 2658 | ** break; */ |
@@ -2400,7 +2663,7 @@ | ||
2400 | 2663 | } |
2401 | 2664 | } |
2402 | 2665 | |
2403 | -/* Run the proprocessor over the input file text. The global variables | |
2666 | +/* Run the preprocessor over the input file text. The global variables | |
2404 | 2667 | ** azDefine[0] through azDefine[nDefine-1] contains the names of all defined |
2405 | 2668 | ** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and |
2406 | 2669 | ** comments them out. Text in between is also commented out as appropriate. |
@@ -2414,7 +2677,7 @@ | ||
2414 | 2677 | for(i=0; z[i]; i++){ |
2415 | 2678 | if( z[i]=='\n' ) lineno++; |
2416 | 2679 | if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue; |
2417 | - if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){ | |
2680 | + if( strncmp(&z[i],"%endif",6)==0 && ISSPACE(z[i+6]) ){ | |
2418 | 2681 | if( exclude ){ |
2419 | 2682 | exclude--; |
2420 | 2683 | if( exclude==0 ){ |
@@ -2422,16 +2685,16 @@ | ||
2422 | 2685 | } |
2423 | 2686 | } |
2424 | 2687 | for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; |
2425 | - }else if( (strncmp(&z[i],"%ifdef",6)==0 && isspace(z[i+6])) | |
2426 | - || (strncmp(&z[i],"%ifndef",7)==0 && isspace(z[i+7])) ){ | |
2688 | + }else if( (strncmp(&z[i],"%ifdef",6)==0 && ISSPACE(z[i+6])) | |
2689 | + || (strncmp(&z[i],"%ifndef",7)==0 && ISSPACE(z[i+7])) ){ | |
2427 | 2690 | if( exclude ){ |
2428 | 2691 | exclude++; |
2429 | 2692 | }else{ |
2430 | - for(j=i+7; isspace(z[j]); j++){} | |
2431 | - for(n=0; z[j+n] && !isspace(z[j+n]); n++){} | |
2693 | + for(j=i+7; ISSPACE(z[j]); j++){} | |
2694 | + for(n=0; z[j+n] && !ISSPACE(z[j+n]); n++){} | |
2432 | 2695 | exclude = 1; |
2433 | 2696 | for(k=0; k<nDefine; k++){ |
2434 | - if( strncmp(azDefine[k],&z[j],n)==0 && strlen(azDefine[k])==n ){ | |
2697 | + if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){ | |
2435 | 2698 | exclude = 0; |
2436 | 2699 | break; |
2437 | 2700 | } |
@@ -2473,8 +2736,7 @@ | ||
2473 | 2736 | ** token is passed to the function "parseonetoken" which builds all |
2474 | 2737 | ** the appropriate data structures in the global state vector "gp". |
2475 | 2738 | */ |
2476 | -void Parse(gp) | |
2477 | -struct lemon *gp; | |
2739 | +void Parse(struct lemon *gp) | |
2478 | 2740 | { |
2479 | 2741 | struct pstate ps; |
2480 | 2742 | FILE *fp; |
@@ -2502,10 +2764,10 @@ | ||
2502 | 2764 | filesize = ftell(fp); |
2503 | 2765 | rewind(fp); |
2504 | 2766 | filebuf = (char *)malloc( filesize+1 ); |
2505 | - if( filebuf==0 ){ | |
2506 | - ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.", | |
2507 | - filesize+1); | |
2767 | + if( filesize>100000000 || filebuf==0 ){ | |
2768 | + ErrorMsg(ps.filename,0,"Input file too large."); | |
2508 | 2769 | gp->errorcnt++; |
2770 | + fclose(fp); | |
2509 | 2771 | return; |
2510 | 2772 | } |
2511 | 2773 | if( fread(filebuf,1,filesize,fp)!=filesize ){ |
@@ -2513,6 +2775,7 @@ | ||
2513 | 2775 | filesize); |
2514 | 2776 | free(filebuf); |
2515 | 2777 | gp->errorcnt++; |
2778 | + fclose(fp); | |
2516 | 2779 | return; |
2517 | 2780 | } |
2518 | 2781 | fclose(fp); |
@@ -2526,7 +2789,7 @@ | ||
2526 | 2789 | lineno = 1; |
2527 | 2790 | for(cp=filebuf; (c= *cp)!=0; ){ |
2528 | 2791 | if( c=='\n' ) lineno++; /* Keep track of the line number */ |
2529 | - if( isspace(c) ){ cp++; continue; } /* Skip all white space */ | |
2792 | + if( ISSPACE(c) ){ cp++; continue; } /* Skip all white space */ | |
2530 | 2793 | if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */ |
2531 | 2794 | cp+=2; |
2532 | 2795 | while( (c= *cp)!=0 && c!='\n' ) cp++; |
@@ -2596,15 +2859,15 @@ | ||
2596 | 2859 | }else{ |
2597 | 2860 | nextcp = cp+1; |
2598 | 2861 | } |
2599 | - }else if( isalnum(c) ){ /* Identifiers */ | |
2600 | - while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++; | |
2862 | + }else if( ISALNUM(c) ){ /* Identifiers */ | |
2863 | + while( (c= *cp)!=0 && (ISALNUM(c) || c=='_') ) cp++; | |
2601 | 2864 | nextcp = cp; |
2602 | 2865 | }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */ |
2603 | 2866 | cp += 3; |
2604 | 2867 | nextcp = cp; |
2605 | - }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){ | |
2868 | + }else if( (c=='/' || c=='|') && ISALPHA(cp[1]) ){ | |
2606 | 2869 | cp += 2; |
2607 | - while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++; | |
2870 | + while( (c = *cp)!=0 && (ISALNUM(c) || c=='_') ) cp++; | |
2608 | 2871 | nextcp = cp; |
2609 | 2872 | }else{ /* All other (one character) operators */ |
2610 | 2873 | cp++; |
@@ -2629,7 +2892,7 @@ | ||
2629 | 2892 | |
2630 | 2893 | /* Allocate a new plink */ |
2631 | 2894 | struct plink *Plink_new(){ |
2632 | - struct plink *new; | |
2895 | + struct plink *newlink; | |
2633 | 2896 | |
2634 | 2897 | if( plink_freelist==0 ){ |
2635 | 2898 | int i; |
@@ -2643,27 +2906,23 @@ | ||
2643 | 2906 | for(i=0; i<amt-1; i++) plink_freelist[i].next = &plink_freelist[i+1]; |
2644 | 2907 | plink_freelist[amt-1].next = 0; |
2645 | 2908 | } |
2646 | - new = plink_freelist; | |
2909 | + newlink = plink_freelist; | |
2647 | 2910 | plink_freelist = plink_freelist->next; |
2648 | - return new; | |
2911 | + return newlink; | |
2649 | 2912 | } |
2650 | 2913 | |
2651 | 2914 | /* Add a plink to a plink list */ |
2652 | -void Plink_add(plpp,cfp) | |
2653 | -struct plink **plpp; | |
2654 | -struct config *cfp; | |
2915 | +void Plink_add(struct plink **plpp, struct config *cfp) | |
2655 | 2916 | { |
2656 | - struct plink *new; | |
2657 | - new = Plink_new(); | |
2658 | - new->next = *plpp; | |
2659 | - *plpp = new; | |
2660 | - new->cfp = cfp; | |
2917 | + struct plink *newlink; | |
2918 | + newlink = Plink_new(); | |
2919 | + newlink->next = *plpp; | |
2920 | + *plpp = newlink; | |
2921 | + newlink->cfp = cfp; | |
2661 | 2922 | } |
2662 | 2923 | |
2663 | 2924 | /* Transfer every plink on the list "from" to the list "to" */ |
2664 | -void Plink_copy(to,from) | |
2665 | -struct plink **to; | |
2666 | -struct plink *from; | |
2925 | +void Plink_copy(struct plink **to, struct plink *from) | |
2667 | 2926 | { |
2668 | 2927 | struct plink *nextpl; |
2669 | 2928 | while( from ){ |
@@ -2675,8 +2934,7 @@ | ||
2675 | 2934 | } |
2676 | 2935 | |
2677 | 2936 | /* Delete every plink on the list */ |
2678 | -void Plink_delete(plp) | |
2679 | -struct plink *plp; | |
2937 | +void Plink_delete(struct plink *plp) | |
2680 | 2938 | { |
2681 | 2939 | struct plink *nextpl; |
2682 | 2940 |
@@ -2696,19 +2954,17 @@ | ||
2696 | 2954 | ** name comes from malloc() and must be freed by the calling |
2697 | 2955 | ** function. |
2698 | 2956 | */ |
2699 | -PRIVATE char *file_makename(lemp,suffix) | |
2700 | -struct lemon *lemp; | |
2701 | -char *suffix; | |
2957 | +PRIVATE char *file_makename(struct lemon *lemp, const char *suffix) | |
2702 | 2958 | { |
2703 | 2959 | char *name; |
2704 | 2960 | char *cp; |
2705 | 2961 | |
2706 | - name = malloc( strlen(lemp->filename) + strlen(suffix) + 5 ); | |
2962 | + name = (char*)malloc( lemonStrlen(lemp->outbasefilename) + lemonStrlen(suffix) + 5 ); | |
2707 | 2963 | if( name==0 ){ |
2708 | 2964 | fprintf(stderr,"Can't allocate space for a filename.\n"); |
2709 | 2965 | exit(1); |
2710 | 2966 | } |
2711 | - strcpy(name,lemp->filename); | |
2967 | + strcpy(name,lemp->outbasefilename); | |
2712 | 2968 | cp = strrchr(name,'.'); |
2713 | 2969 | if( cp ) *cp = 0; |
2714 | 2970 | strcat(name,suffix); |
@@ -2718,11 +2974,11 @@ | ||
2718 | 2974 | /* Open a file with a name based on the name of the input file, |
2719 | 2975 | ** but with a different (specified) suffix, and return a pointer |
2720 | 2976 | ** to the stream */ |
2721 | -PRIVATE FILE *file_open(lemp,suffix,mode) | |
2722 | -struct lemon *lemp; | |
2723 | -char *suffix; | |
2724 | -char *mode; | |
2725 | -{ | |
2977 | +PRIVATE FILE *file_open( | |
2978 | + struct lemon *lemp, | |
2979 | + const char *suffix, | |
2980 | + const char *mode | |
2981 | +){ | |
2726 | 2982 | FILE *fp; |
2727 | 2983 | |
2728 | 2984 | if( lemp->outname ) free(lemp->outname); |
@@ -2738,8 +2994,7 @@ | ||
2738 | 2994 | |
2739 | 2995 | /* Duplicate the input file without comments and without actions |
2740 | 2996 | ** on rules */ |
2741 | -void Reprint(lemp) | |
2742 | -struct lemon *lemp; | |
2997 | +void Reprint(struct lemon *lemp) | |
2743 | 2998 | { |
2744 | 2999 | struct rule *rp; |
2745 | 3000 | struct symbol *sp; |
@@ -2748,7 +3003,7 @@ | ||
2748 | 3003 | maxlen = 10; |
2749 | 3004 | for(i=0; i<lemp->nsymbol; i++){ |
2750 | 3005 | sp = lemp->symbols[i]; |
2751 | - len = (int)strlen(sp->name); | |
3006 | + len = lemonStrlen(sp->name); | |
2752 | 3007 | if( len>maxlen ) maxlen = len; |
2753 | 3008 | } |
2754 | 3009 | ncolumns = 76/(maxlen+5); |
@@ -2769,11 +3024,13 @@ | ||
2769 | 3024 | printf(" ::="); |
2770 | 3025 | for(i=0; i<rp->nrhs; i++){ |
2771 | 3026 | sp = rp->rhs[i]; |
2772 | - printf(" %s", sp->name); | |
2773 | 3027 | if( sp->type==MULTITERMINAL ){ |
3028 | + printf(" %s", sp->subsym[0]->name); | |
2774 | 3029 | for(j=1; j<sp->nsubsym; j++){ |
2775 | 3030 | printf("|%s", sp->subsym[j]->name); |
2776 | 3031 | } |
3032 | + }else{ | |
3033 | + printf(" %s", sp->name); | |
2777 | 3034 | } |
2778 | 3035 | /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */ |
2779 | 3036 | } |
@@ -2784,28 +3041,33 @@ | ||
2784 | 3041 | } |
2785 | 3042 | } |
2786 | 3043 | |
2787 | -void ConfigPrint(fp,cfp) | |
2788 | -FILE *fp; | |
2789 | -struct config *cfp; | |
2790 | -{ | |
2791 | - struct rule *rp; | |
3044 | +/* Print a single rule. | |
3045 | +*/ | |
3046 | +void RulePrint(FILE *fp, struct rule *rp, int iCursor){ | |
2792 | 3047 | struct symbol *sp; |
2793 | 3048 | int i, j; |
2794 | - rp = cfp->rp; | |
2795 | 3049 | fprintf(fp,"%s ::=",rp->lhs->name); |
2796 | 3050 | for(i=0; i<=rp->nrhs; i++){ |
2797 | - if( i==cfp->dot ) fprintf(fp," *"); | |
3051 | + if( i==iCursor ) fprintf(fp," *"); | |
2798 | 3052 | if( i==rp->nrhs ) break; |
2799 | 3053 | sp = rp->rhs[i]; |
2800 | - fprintf(fp," %s", sp->name); | |
2801 | 3054 | if( sp->type==MULTITERMINAL ){ |
3055 | + fprintf(fp," %s", sp->subsym[0]->name); | |
2802 | 3056 | for(j=1; j<sp->nsubsym; j++){ |
2803 | 3057 | fprintf(fp,"|%s",sp->subsym[j]->name); |
2804 | 3058 | } |
3059 | + }else{ | |
3060 | + fprintf(fp," %s", sp->name); | |
2805 | 3061 | } |
2806 | 3062 | } |
2807 | 3063 | } |
2808 | 3064 | |
3065 | +/* Print the rule for a configuration. | |
3066 | +*/ | |
3067 | +void ConfigPrint(FILE *fp, struct config *cfp){ | |
3068 | + RulePrint(fp, cfp->rp, cfp->dot); | |
3069 | +} | |
3070 | + | |
2809 | 3071 | /* #define TEST */ |
2810 | 3072 | #if 0 |
2811 | 3073 | /* Print a set */ |
@@ -2845,15 +3107,30 @@ | ||
2845 | 3107 | /* Print an action to the given file descriptor. Return FALSE if |
2846 | 3108 | ** nothing was actually printed. |
2847 | 3109 | */ |
2848 | -int PrintAction(struct action *ap, FILE *fp, int indent){ | |
3110 | +int PrintAction( | |
3111 | + struct action *ap, /* The action to print */ | |
3112 | + FILE *fp, /* Print the action here */ | |
3113 | + int indent /* Indent by this amount */ | |
3114 | +){ | |
2849 | 3115 | int result = 1; |
2850 | 3116 | switch( ap->type ){ |
2851 | - case SHIFT: | |
2852 | - fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum); | |
3117 | + case SHIFT: { | |
3118 | + struct state *stp = ap->x.stp; | |
3119 | + fprintf(fp,"%*s shift %-7d",indent,ap->sp->name,stp->statenum); | |
2853 | 3120 | break; |
2854 | - case REDUCE: | |
2855 | - fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index); | |
3121 | + } | |
3122 | + case REDUCE: { | |
3123 | + struct rule *rp = ap->x.rp; | |
3124 | + fprintf(fp,"%*s reduce %-7d",indent,ap->sp->name,rp->iRule); | |
3125 | + RulePrint(fp, rp, -1); | |
2856 | 3126 | break; |
3127 | + } | |
3128 | + case SHIFTREDUCE: { | |
3129 | + struct rule *rp = ap->x.rp; | |
3130 | + fprintf(fp,"%*s shift-reduce %-7d",indent,ap->sp->name,rp->iRule); | |
3131 | + RulePrint(fp, rp, -1); | |
3132 | + break; | |
3133 | + } | |
2857 | 3134 | case ACCEPT: |
2858 | 3135 | fprintf(fp,"%*s accept",indent,ap->sp->name); |
2859 | 3136 | break; |
@@ -2862,25 +3139,41 @@ | ||
2862 | 3139 | break; |
2863 | 3140 | case SRCONFLICT: |
2864 | 3141 | case RRCONFLICT: |
2865 | - fprintf(fp,"%*s reduce %-3d ** Parsing conflict **", | |
2866 | - indent,ap->sp->name,ap->x.rp->index); | |
3142 | + fprintf(fp,"%*s reduce %-7d ** Parsing conflict **", | |
3143 | + indent,ap->sp->name,ap->x.rp->iRule); | |
2867 | 3144 | break; |
2868 | 3145 | case SSCONFLICT: |
2869 | - fprintf(fp,"%*s shift %d ** Parsing conflict **", | |
3146 | + fprintf(fp,"%*s shift %-7d ** Parsing conflict **", | |
2870 | 3147 | indent,ap->sp->name,ap->x.stp->statenum); |
2871 | 3148 | break; |
2872 | 3149 | case SH_RESOLVED: |
3150 | + if( showPrecedenceConflict ){ | |
3151 | + fprintf(fp,"%*s shift %-7d -- dropped by precedence", | |
3152 | + indent,ap->sp->name,ap->x.stp->statenum); | |
3153 | + }else{ | |
3154 | + result = 0; | |
3155 | + } | |
3156 | + break; | |
2873 | 3157 | case RD_RESOLVED: |
3158 | + if( showPrecedenceConflict ){ | |
3159 | + fprintf(fp,"%*s reduce %-7d -- dropped by precedence", | |
3160 | + indent,ap->sp->name,ap->x.rp->iRule); | |
3161 | + }else{ | |
3162 | + result = 0; | |
3163 | + } | |
3164 | + break; | |
2874 | 3165 | case NOT_USED: |
2875 | 3166 | result = 0; |
2876 | 3167 | break; |
2877 | 3168 | } |
3169 | + if( result && ap->spOpt ){ | |
3170 | + fprintf(fp," /* because %s==%s */", ap->sp->name, ap->spOpt->name); | |
3171 | + } | |
2878 | 3172 | return result; |
2879 | 3173 | } |
2880 | 3174 | |
2881 | -/* Generate the "y.output" log file */ | |
2882 | -void ReportOutput(lemp) | |
2883 | -struct lemon *lemp; | |
3175 | +/* Generate the "*.out" log file */ | |
3176 | +void ReportOutput(struct lemon *lemp) | |
2884 | 3177 | { |
2885 | 3178 | int i; |
2886 | 3179 | struct state *stp; |
@@ -2890,7 +3183,7 @@ | ||
2890 | 3183 | |
2891 | 3184 | fp = file_open(lemp,".out","wb"); |
2892 | 3185 | if( fp==0 ) return; |
2893 | - for(i=0; i<lemp->nstate; i++){ | |
3186 | + for(i=0; i<lemp->nxstate; i++){ | |
2894 | 3187 | stp = lemp->sorted[i]; |
2895 | 3188 | fprintf(fp,"State %d:\n",stp->statenum); |
2896 | 3189 | if( lemp->basisflag ) cfp=stp->bp; |
@@ -2898,7 +3191,7 @@ | ||
2898 | 3191 | while( cfp ){ |
2899 | 3192 | char buf[20]; |
2900 | 3193 | if( cfp->dot==cfp->rp->nrhs ){ |
2901 | - sprintf(buf,"(%d)",cfp->rp->index); | |
3194 | + sprintf(buf,"(%d)",cfp->rp->iRule); | |
2902 | 3195 | fprintf(fp," %5s ",buf); |
2903 | 3196 | }else{ |
2904 | 3197 | fprintf(fp," "); |
@@ -2946,17 +3239,16 @@ | ||
2946 | 3239 | |
2947 | 3240 | /* Search for the file "name" which is in the same directory as |
2948 | 3241 | ** the exacutable */ |
2949 | -PRIVATE char *pathsearch(argv0,name,modemask) | |
2950 | -char *argv0; | |
2951 | -char *name; | |
2952 | -int modemask; | |
3242 | +PRIVATE char *pathsearch(char *argv0, char *name, int modemask) | |
2953 | 3243 | { |
2954 | - char *pathlist; | |
3244 | + const char *pathlist; | |
3245 | + char *pathbufptr; | |
3246 | + char *pathbuf; | |
2955 | 3247 | char *path,*cp; |
2956 | 3248 | char c; |
2957 | 3249 | |
2958 | 3250 | #ifdef __WIN32__ |
2959 | - for (cp = argv0 + strlen(argv0); cp-- > argv0; ) | |
3251 | + for (cp = argv0 + lemonStrlen(argv0); cp-- > argv0; ) | |
2960 | 3252 | { |
2961 | 3253 | if( *cp == '\\' || *cp == '/' ) |
2962 | 3254 | break; |
@@ -2967,26 +3259,29 @@ | ||
2967 | 3259 | if( cp ){ |
2968 | 3260 | c = *cp; |
2969 | 3261 | *cp = 0; |
2970 | - path = (char *)malloc( strlen(argv0) + strlen(name) + 2 ); | |
3262 | + path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 ); | |
2971 | 3263 | if( path ) sprintf(path,"%s/%s",argv0,name); |
2972 | 3264 | *cp = c; |
2973 | 3265 | }else{ |
2974 | - extern char *getenv(); | |
2975 | 3266 | pathlist = getenv("PATH"); |
2976 | 3267 | if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; |
2977 | - path = (char *)malloc( strlen(pathlist)+strlen(name)+2 ); | |
2978 | - if( path!=0 ){ | |
2979 | - while( *pathlist ){ | |
2980 | - cp = strchr(pathlist,':'); | |
2981 | - if( cp==0 ) cp = &pathlist[strlen(pathlist)]; | |
3268 | + pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 ); | |
3269 | + path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 ); | |
3270 | + if( (pathbuf != 0) && (path!=0) ){ | |
3271 | + pathbufptr = pathbuf; | |
3272 | + strcpy(pathbuf, pathlist); | |
3273 | + while( *pathbuf ){ | |
3274 | + cp = strchr(pathbuf,':'); | |
3275 | + if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)]; | |
2982 | 3276 | c = *cp; |
2983 | 3277 | *cp = 0; |
2984 | - sprintf(path,"%s/%s",pathlist,name); | |
3278 | + sprintf(path,"%s/%s",pathbuf,name); | |
2985 | 3279 | *cp = c; |
2986 | - if( c==0 ) pathlist = ""; | |
2987 | - else pathlist = &cp[1]; | |
3280 | + if( c==0 ) pathbuf[0] = 0; | |
3281 | + else pathbuf = &cp[1]; | |
2988 | 3282 | if( access(path,modemask)==0 ) break; |
2989 | 3283 | } |
3284 | + free(pathbufptr); | |
2990 | 3285 | } |
2991 | 3286 | } |
2992 | 3287 | return path; |
@@ -2996,16 +3291,15 @@ | ||
2996 | 3291 | ** which is to be put in the action table of the generated machine. |
2997 | 3292 | ** Return negative if no action should be generated. |
2998 | 3293 | */ |
2999 | -PRIVATE int compute_action(lemp,ap) | |
3000 | -struct lemon *lemp; | |
3001 | -struct action *ap; | |
3294 | +PRIVATE int compute_action(struct lemon *lemp, struct action *ap) | |
3002 | 3295 | { |
3003 | 3296 | int act; |
3004 | 3297 | switch( ap->type ){ |
3005 | - case SHIFT: act = ap->x.stp->statenum; break; | |
3006 | - case REDUCE: act = ap->x.rp->index + lemp->nstate; break; | |
3007 | - case ERROR: act = lemp->nstate + lemp->nrule; break; | |
3008 | - case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break; | |
3298 | + case SHIFT: act = ap->x.stp->statenum; break; | |
3299 | + case SHIFTREDUCE: act = ap->x.rp->iRule + lemp->nstate; break; | |
3300 | + case REDUCE: act = ap->x.rp->iRule + lemp->nstate+lemp->nrule; break; | |
3301 | + case ERROR: act = lemp->nstate + lemp->nrule*2; break; | |
3302 | + case ACCEPT: act = lemp->nstate + lemp->nrule*2 + 1; break; | |
3009 | 3303 | default: act = -1; break; |
3010 | 3304 | } |
3011 | 3305 | return act; |
@@ -3021,11 +3315,7 @@ | ||
3021 | 3315 | ** if name!=0, then any word that begin with "Parse" is changed to |
3022 | 3316 | ** begin with *name instead. |
3023 | 3317 | */ |
3024 | -PRIVATE void tplt_xfer(name,in,out,lineno) | |
3025 | -char *name; | |
3026 | -FILE *in; | |
3027 | -FILE *out; | |
3028 | -int *lineno; | |
3318 | +PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno) | |
3029 | 3319 | { |
3030 | 3320 | int i, iStart; |
3031 | 3321 | char line[LINESIZE]; |
@@ -3035,7 +3325,7 @@ | ||
3035 | 3325 | if( name ){ |
3036 | 3326 | for(i=0; line[i]; i++){ |
3037 | 3327 | if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0 |
3038 | - && (i==0 || !isalpha(line[i-1])) | |
3328 | + && (i==0 || !ISALPHA(line[i-1])) | |
3039 | 3329 | ){ |
3040 | 3330 | if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]); |
3041 | 3331 | fprintf(out,"%s",name); |
@@ -3050,14 +3340,32 @@ | ||
3050 | 3340 | |
3051 | 3341 | /* The next function finds the template file and opens it, returning |
3052 | 3342 | ** a pointer to the opened file. */ |
3053 | -PRIVATE FILE *tplt_open(lemp) | |
3054 | -struct lemon *lemp; | |
3343 | +PRIVATE FILE *tplt_open(struct lemon *lemp) | |
3055 | 3344 | { |
3056 | 3345 | static char templatename[] = "lempar.c"; |
3057 | 3346 | char buf[1000]; |
3058 | 3347 | FILE *in; |
3059 | 3348 | char *tpltname; |
3060 | 3349 | char *cp; |
3350 | + Boolean tpltnameinbuf; | |
3351 | + | |
3352 | + /* first, see if user specified a template filename on the command line. */ | |
3353 | + if (user_templatename != 0) { | |
3354 | + if( access(user_templatename,004)==-1 ){ | |
3355 | + fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", | |
3356 | + user_templatename); | |
3357 | + lemp->errorcnt++; | |
3358 | + return 0; | |
3359 | + } | |
3360 | + in = fopen(user_templatename,"rb"); | |
3361 | + if( in==0 ){ | |
3362 | + fprintf(stderr,"Can't open the template file \"%s\".\n", | |
3363 | + user_templatename); | |
3364 | + lemp->errorcnt++; | |
3365 | + return 0; | |
3366 | + } | |
3367 | + return in; | |
3368 | + } | |
3061 | 3369 | |
3062 | 3370 | cp = strrchr(lemp->filename,'.'); |
3063 | 3371 | if( cp ){ |
@@ -3067,10 +3375,13 @@ | ||
3067 | 3375 | } |
3068 | 3376 | if( access(buf,004)==0 ){ |
3069 | 3377 | tpltname = buf; |
3378 | + tpltnameinbuf = LEMON_TRUE; | |
3070 | 3379 | }else if( access(templatename,004)==0 ){ |
3071 | 3380 | tpltname = templatename; |
3381 | + tpltnameinbuf = LEMON_TRUE; | |
3072 | 3382 | }else{ |
3073 | 3383 | tpltname = pathsearch(lemp->argv0,templatename,0); |
3384 | + tpltnameinbuf = LEMON_FALSE; | |
3074 | 3385 | } |
3075 | 3386 | if( tpltname==0 ){ |
3076 | 3387 | fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", |
@@ -3081,17 +3392,16 @@ | ||
3081 | 3392 | in = fopen(tpltname,"rb"); |
3082 | 3393 | if( in==0 ){ |
3083 | 3394 | fprintf(stderr,"Can't open the template file \"%s\".\n",templatename); |
3395 | + if (tpltnameinbuf == LEMON_FALSE) free(tpltname); | |
3084 | 3396 | lemp->errorcnt++; |
3085 | 3397 | return 0; |
3086 | 3398 | } |
3399 | + if (tpltnameinbuf == LEMON_FALSE) free(tpltname); | |
3087 | 3400 | return in; |
3088 | 3401 | } |
3089 | 3402 | |
3090 | 3403 | /* Print a #line directive line to the output file. */ |
3091 | -PRIVATE void tplt_linedir(out,lineno,filename) | |
3092 | -FILE *out; | |
3093 | -int lineno; | |
3094 | -char *filename; | |
3404 | +PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename) | |
3095 | 3405 | { |
3096 | 3406 | fprintf(out,"#line %d \"",lineno); |
3097 | 3407 | while( *filename ){ |
@@ -3103,16 +3413,9 @@ | ||
3103 | 3413 | } |
3104 | 3414 | |
3105 | 3415 | /* Print a string to the file and keep the linenumber up to date */ |
3106 | -PRIVATE void tplt_print(out,lemp,str,strln,lineno) | |
3107 | -FILE *out; | |
3108 | -struct lemon *lemp; | |
3109 | -char *str; | |
3110 | -int strln; | |
3111 | -int *lineno; | |
3416 | +PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno) | |
3112 | 3417 | { |
3113 | 3418 | if( str==0 ) return; |
3114 | - tplt_linedir(out,strln,lemp->filename); | |
3115 | - (*lineno)++; | |
3116 | 3419 | while( *str ){ |
3117 | 3420 | if( *str=='\n' ) (*lineno)++; |
3118 | 3421 | putc(*str,out); |
@@ -3122,8 +3425,10 @@ | ||
3122 | 3425 | putc('\n',out); |
3123 | 3426 | (*lineno)++; |
3124 | 3427 | } |
3125 | - tplt_linedir(out,*lineno+1,lemp->outname); | |
3126 | - (*lineno)+=1; | |
3428 | + if (!lemp->nolinenosflag) { | |
3429 | + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); | |
3430 | + } | |
3431 | + | |
3127 | 3432 | return; |
3128 | 3433 | } |
3129 | 3434 |
@@ -3131,29 +3436,29 @@ | ||
3131 | 3436 | ** The following routine emits code for the destructor for the |
3132 | 3437 | ** symbol sp |
3133 | 3438 | */ |
3134 | -void emit_destructor_code(out,sp,lemp,lineno) | |
3135 | -FILE *out; | |
3136 | -struct symbol *sp; | |
3137 | -struct lemon *lemp; | |
3138 | -int *lineno; | |
3139 | -{ | |
3439 | +void emit_destructor_code( | |
3440 | + FILE *out, | |
3441 | + struct symbol *sp, | |
3442 | + struct lemon *lemp, | |
3443 | + int *lineno | |
3444 | +){ | |
3140 | 3445 | char *cp = 0; |
3141 | 3446 | |
3142 | - int linecnt = 0; | |
3143 | 3447 | if( sp->type==TERMINAL ){ |
3144 | 3448 | cp = lemp->tokendest; |
3145 | 3449 | if( cp==0 ) return; |
3146 | - tplt_linedir(out,lemp->tokendestln,lemp->filename); | |
3147 | - fprintf(out,"{"); | |
3450 | + fprintf(out,"{\n"); (*lineno)++; | |
3148 | 3451 | }else if( sp->destructor ){ |
3149 | 3452 | cp = sp->destructor; |
3150 | - tplt_linedir(out,sp->destructorln,lemp->filename); | |
3151 | - fprintf(out,"{"); | |
3453 | + fprintf(out,"{\n"); (*lineno)++; | |
3454 | + if( !lemp->nolinenosflag ){ | |
3455 | + (*lineno)++; | |
3456 | + tplt_linedir(out,sp->destLineno,lemp->filename); | |
3457 | + } | |
3152 | 3458 | }else if( lemp->vardest ){ |
3153 | 3459 | cp = lemp->vardest; |
3154 | 3460 | if( cp==0 ) return; |
3155 | - tplt_linedir(out,lemp->vardestln,lemp->filename); | |
3156 | - fprintf(out,"{"); | |
3461 | + fprintf(out,"{\n"); (*lineno)++; | |
3157 | 3462 | }else{ |
3158 | 3463 | assert( 0 ); /* Cannot happen */ |
3159 | 3464 | } |
@@ -3163,21 +3468,21 @@ | ||
3163 | 3468 | cp++; |
3164 | 3469 | continue; |
3165 | 3470 | } |
3166 | - if( *cp=='\n' ) linecnt++; | |
3471 | + if( *cp=='\n' ) (*lineno)++; | |
3167 | 3472 | fputc(*cp,out); |
3168 | 3473 | } |
3169 | - (*lineno) += 3 + linecnt; | |
3170 | - fprintf(out,"}\n"); | |
3171 | - tplt_linedir(out,*lineno,lemp->outname); | |
3474 | + fprintf(out,"\n"); (*lineno)++; | |
3475 | + if (!lemp->nolinenosflag) { | |
3476 | + (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); | |
3477 | + } | |
3478 | + fprintf(out,"}\n"); (*lineno)++; | |
3172 | 3479 | return; |
3173 | 3480 | } |
3174 | 3481 | |
3175 | 3482 | /* |
3176 | 3483 | ** Return TRUE (non-zero) if the given symbol has a destructor. |
3177 | 3484 | */ |
3178 | -int has_destructor(sp, lemp) | |
3179 | -struct symbol *sp; | |
3180 | -struct lemon *lemp; | |
3485 | +int has_destructor(struct symbol *sp, struct lemon *lemp) | |
3181 | 3486 | { |
3182 | 3487 | int ret; |
3183 | 3488 | if( sp->type==TERMINAL ){ |
@@ -3200,14 +3505,15 @@ | ||
3200 | 3505 | ** |
3201 | 3506 | ** If n==-1, then the previous character is overwritten. |
3202 | 3507 | */ |
3203 | -PRIVATE char *append_str(char *zText, int n, int p1, int p2, int bNoSubst){ | |
3508 | +PRIVATE char *append_str(const char *zText, int n, int p1, int p2, int bNoSubst){ | |
3509 | + static char empty[1] = { 0 }; | |
3204 | 3510 | static char *z = 0; |
3205 | 3511 | static int alloced = 0; |
3206 | 3512 | static int used = 0; |
3207 | 3513 | int c; |
3208 | 3514 | char zInt[40]; |
3209 | - | |
3210 | 3515 | if( zText==0 ){ |
3516 | + if( used==0 && z!=0 ) z[0] = 0; | |
3211 | 3517 | used = 0; |
3212 | 3518 | return z; |
3213 | 3519 | } |
@@ -3216,20 +3522,20 @@ | ||
3216 | 3522 | used += n; |
3217 | 3523 | assert( used>=0 ); |
3218 | 3524 | } |
3219 | - n = (int)strlen(zText); | |
3525 | + n = lemonStrlen(zText); | |
3220 | 3526 | } |
3221 | 3527 | if( n+sizeof(zInt)*2+used >= (size_t)alloced ){ |
3222 | 3528 | alloced = n + sizeof(zInt)*2 + used + 200; |
3223 | - z = realloc(z, alloced); | |
3224 | - } | |
3225 | - if( z==0 ) return ""; | |
3529 | + z = (char *) realloc(z, alloced); | |
3530 | + } | |
3531 | + if( z==0 ) return empty; | |
3226 | 3532 | while( n-- > 0 ){ |
3227 | 3533 | c = *(zText++); |
3228 | 3534 | if( !bNoSubst && c=='%' && n>0 && zText[0]=='d' ){ |
3229 | 3535 | sprintf(zInt, "%d", p1); |
3230 | 3536 | p1 = p2; |
3231 | 3537 | strcpy(&z[used], zInt); |
3232 | - used += (int)strlen(&z[used]); | |
3538 | + used += lemonStrlen(&z[used]); | |
3233 | 3539 | zText++; |
3234 | 3540 | n--; |
3235 | 3541 | }else{ |
@@ -3241,39 +3547,112 @@ | ||
3241 | 3547 | } |
3242 | 3548 | |
3243 | 3549 | /* |
3244 | -** zCode is a string that is the action associated with a rule. Expand | |
3245 | -** the symbols in this string so that the refer to elements of the parser | |
3246 | -** stack. | |
3550 | +** Write and transform the rp->code string so that symbols are expanded. | |
3551 | +** Populate the rp->codePrefix and rp->codeSuffix strings, as appropriate. | |
3552 | +** | |
3553 | +** Return 1 if the expanded code requires that "yylhsminor" local variable | |
3554 | +** to be defined. | |
3247 | 3555 | */ |
3248 | -PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ | |
3556 | +PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){ | |
3249 | 3557 | char *cp, *xp; |
3250 | 3558 | int i; |
3251 | - char lhsused = 0; /* True if the LHS element has been used */ | |
3252 | - char used[MAXRHS]; /* True for each RHS element which is used */ | |
3559 | + int rc = 0; /* True if yylhsminor is used */ | |
3560 | + int dontUseRhs0 = 0; /* If true, use of left-most RHS label is illegal */ | |
3561 | + const char *zSkip = 0; /* The zOvwrt comment within rp->code, or NULL */ | |
3562 | + char lhsused = 0; /* True if the LHS element has been used */ | |
3563 | + char lhsdirect; /* True if LHS writes directly into stack */ | |
3564 | + char used[MAXRHS]; /* True for each RHS element which is used */ | |
3565 | + char zLhs[50]; /* Convert the LHS symbol into this string */ | |
3566 | + char zOvwrt[900]; /* Comment that to allow LHS to overwrite RHS */ | |
3253 | 3567 | |
3254 | 3568 | for(i=0; i<rp->nrhs; i++) used[i] = 0; |
3255 | 3569 | lhsused = 0; |
3256 | 3570 | |
3257 | 3571 | if( rp->code==0 ){ |
3258 | - rp->code = "\n"; | |
3259 | - rp->line = rp->ruleline; | |
3572 | + static char newlinestr[2] = { '\n', '\0' }; | |
3573 | + rp->code = newlinestr; | |
3574 | + rp->line = rp->ruleline; | |
3575 | + rp->noCode = 1; | |
3576 | + }else{ | |
3577 | + rp->noCode = 0; | |
3578 | + } | |
3579 | + | |
3580 | + if( rp->nrhs==0 ){ | |
3581 | + /* If there are no RHS symbols, then writing directly to the LHS is ok */ | |
3582 | + lhsdirect = 1; | |
3583 | + }else if( rp->rhsalias[0]==0 ){ | |
3584 | + /* The left-most RHS symbol has not value. LHS direct is ok. But | |
3585 | + ** we have to call the distructor on the RHS symbol first. */ | |
3586 | + lhsdirect = 1; | |
3587 | + if( has_destructor(rp->rhs[0],lemp) ){ | |
3588 | + append_str(0,0,0,0,0); | |
3589 | + append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, | |
3590 | + rp->rhs[0]->index,1-rp->nrhs,0); | |
3591 | + rp->codePrefix = Strsafe(append_str(0,0,0,0,0)); | |
3592 | + rp->noCode = 0; | |
3593 | + } | |
3594 | + }else if( rp->lhsalias==0 ){ | |
3595 | + /* There is no LHS value symbol. */ | |
3596 | + lhsdirect = 1; | |
3597 | + }else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){ | |
3598 | + /* The LHS symbol and the left-most RHS symbol are the same, so | |
3599 | + ** direct writing is allowed */ | |
3600 | + lhsdirect = 1; | |
3601 | + lhsused = 1; | |
3602 | + used[0] = 1; | |
3603 | + if( rp->lhs->dtnum!=rp->rhs[0]->dtnum ){ | |
3604 | + ErrorMsg(lemp->filename,rp->ruleline, | |
3605 | + "%s(%s) and %s(%s) share the same label but have " | |
3606 | + "different datatypes.", | |
3607 | + rp->lhs->name, rp->lhsalias, rp->rhs[0]->name, rp->rhsalias[0]); | |
3608 | + lemp->errorcnt++; | |
3609 | + } | |
3610 | + }else{ | |
3611 | + sprintf(zOvwrt, "/*%s-overwrites-%s*/", rp->lhsalias, rp->rhsalias[0]); | |
3612 | + zSkip = strstr(rp->code, zOvwrt); | |
3613 | + if( zSkip!=0 ){ | |
3614 | + /* The code contains a special comment that indicates that it is safe | |
3615 | + ** for the LHS label to overwrite left-most RHS label. */ | |
3616 | + lhsdirect = 1; | |
3617 | + }else{ | |
3618 | + lhsdirect = 0; | |
3619 | + } | |
3620 | + } | |
3621 | + if( lhsdirect ){ | |
3622 | + sprintf(zLhs, "yymsp[%d].minor.yy%d",1-rp->nrhs,rp->lhs->dtnum); | |
3623 | + }else{ | |
3624 | + rc = 1; | |
3625 | + sprintf(zLhs, "yylhsminor.yy%d",rp->lhs->dtnum); | |
3260 | 3626 | } |
3261 | 3627 | |
3262 | 3628 | append_str(0,0,0,0,0); |
3263 | - for(cp=rp->code; *cp; cp++){ | |
3264 | - if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){ | |
3629 | + | |
3630 | + /* This const cast is wrong but harmless, if we're careful. */ | |
3631 | + for(cp=(char *)rp->code; *cp; cp++){ | |
3632 | + if( cp==zSkip ){ | |
3633 | + append_str(zOvwrt,0,0,0,0); | |
3634 | + cp += lemonStrlen(zOvwrt)-1; | |
3635 | + dontUseRhs0 = 1; | |
3636 | + continue; | |
3637 | + } | |
3638 | + if( ISALPHA(*cp) && (cp==rp->code || (!ISALNUM(cp[-1]) && cp[-1]!='_')) ){ | |
3265 | 3639 | char saved; |
3266 | - for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++); | |
3640 | + for(xp= &cp[1]; ISALNUM(*xp) || *xp=='_'; xp++); | |
3267 | 3641 | saved = *xp; |
3268 | 3642 | *xp = 0; |
3269 | 3643 | if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){ |
3270 | - append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0,0); | |
3644 | + append_str(zLhs,0,0,0,0); | |
3271 | 3645 | cp = xp; |
3272 | 3646 | lhsused = 1; |
3273 | 3647 | }else{ |
3274 | 3648 | for(i=0; i<rp->nrhs; i++){ |
3275 | 3649 | if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){ |
3276 | - if( cp!=rp->code && cp[-1]=='@' ){ | |
3650 | + if( i==0 && dontUseRhs0 ){ | |
3651 | + ErrorMsg(lemp->filename,rp->ruleline, | |
3652 | + "Label %s used after '%s'.", | |
3653 | + rp->rhsalias[0], zOvwrt); | |
3654 | + lemp->errorcnt++; | |
3655 | + }else if( cp!=rp->code && cp[-1]=='@' ){ | |
3277 | 3656 | /* If the argument is of the form @X then substituted |
3278 | 3657 | ** the token number of X, not the value of X */ |
3279 | 3658 | append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0,0); |
@@ -3298,6 +3677,11 @@ | ||
3298 | 3677 | append_str(cp, 1, 0, 0, 1); |
3299 | 3678 | } /* End loop */ |
3300 | 3679 | |
3680 | + /* Main code generation completed */ | |
3681 | + cp = append_str(0,0,0,0,0); | |
3682 | + if( cp && cp[0] ) rp->code = Strsafe(cp); | |
3683 | + append_str(0,0,0,0,0); | |
3684 | + | |
3301 | 3685 | /* Check to make sure the LHS has been used */ |
3302 | 3686 | if( rp->lhsalias && !lhsused ){ |
3303 | 3687 | ErrorMsg(lemp->filename,rp->ruleline, |
@@ -3306,53 +3690,102 @@ | ||
3306 | 3690 | lemp->errorcnt++; |
3307 | 3691 | } |
3308 | 3692 | |
3309 | - /* Generate destructor code for RHS symbols which are not used in the | |
3310 | - ** reduce code */ | |
3693 | + /* Generate destructor code for RHS minor values which are not referenced. | |
3694 | + ** Generate error messages for unused labels and duplicate labels. | |
3695 | + */ | |
3311 | 3696 | for(i=0; i<rp->nrhs; i++){ |
3312 | - if( rp->rhsalias[i] && !used[i] ){ | |
3313 | - ErrorMsg(lemp->filename,rp->ruleline, | |
3314 | - "Label %s for \"%s(%s)\" is never used.", | |
3315 | - rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); | |
3316 | - lemp->errorcnt++; | |
3317 | - }else if( rp->rhsalias[i]==0 ){ | |
3318 | - if( has_destructor(rp->rhs[i],lemp) ){ | |
3319 | - append_str(" yy_destructor(%d,&yymsp[%d].minor);\n", 0, | |
3320 | - rp->rhs[i]->index,i-rp->nrhs+1,0); | |
3321 | - }else{ | |
3322 | - /* No destructor defined for this term */ | |
3697 | + if( rp->rhsalias[i] ){ | |
3698 | + if( i>0 ){ | |
3699 | + int j; | |
3700 | + if( rp->lhsalias && strcmp(rp->lhsalias,rp->rhsalias[i])==0 ){ | |
3701 | + ErrorMsg(lemp->filename,rp->ruleline, | |
3702 | + "%s(%s) has the same label as the LHS but is not the left-most " | |
3703 | + "symbol on the RHS.", | |
3704 | + rp->rhs[i]->name, rp->rhsalias); | |
3705 | + lemp->errorcnt++; | |
3706 | + } | |
3707 | + for(j=0; j<i; j++){ | |
3708 | + if( rp->rhsalias[j] && strcmp(rp->rhsalias[j],rp->rhsalias[i])==0 ){ | |
3709 | + ErrorMsg(lemp->filename,rp->ruleline, | |
3710 | + "Label %s used for multiple symbols on the RHS of a rule.", | |
3711 | + rp->rhsalias[i]); | |
3712 | + lemp->errorcnt++; | |
3713 | + break; | |
3714 | + } | |
3715 | + } | |
3323 | 3716 | } |
3717 | + if( !used[i] ){ | |
3718 | + ErrorMsg(lemp->filename,rp->ruleline, | |
3719 | + "Label %s for \"%s(%s)\" is never used.", | |
3720 | + rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); | |
3721 | + lemp->errorcnt++; | |
3722 | + } | |
3723 | + }else if( i>0 && has_destructor(rp->rhs[i],lemp) ){ | |
3724 | + append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, | |
3725 | + rp->rhs[i]->index,i-rp->nrhs+1,0); | |
3324 | 3726 | } |
3325 | 3727 | } |
3326 | - if( rp->code ){ | |
3327 | - cp = append_str(0,0,0,0,0); | |
3328 | - rp->code = Strsafe(cp?cp:""); | |
3329 | - } | |
3728 | + | |
3729 | + /* If unable to write LHS values directly into the stack, write the | |
3730 | + ** saved LHS value now. */ | |
3731 | + if( lhsdirect==0 ){ | |
3732 | + append_str(" yymsp[%d].minor.yy%d = ", 0, 1-rp->nrhs, rp->lhs->dtnum, 0); | |
3733 | + append_str(zLhs, 0, 0, 0, 0); | |
3734 | + append_str(";\n", 0, 0, 0, 0); | |
3735 | + } | |
3736 | + | |
3737 | + /* Suffix code generation complete */ | |
3738 | + cp = append_str(0,0,0,0,0); | |
3739 | + if( cp && cp[0] ){ | |
3740 | + rp->codeSuffix = Strsafe(cp); | |
3741 | + rp->noCode = 0; | |
3742 | + } | |
3743 | + | |
3744 | + return rc; | |
3330 | 3745 | } |
3331 | 3746 | |
3332 | 3747 | /* |
3333 | 3748 | ** Generate code which executes when the rule "rp" is reduced. Write |
3334 | 3749 | ** the code to "out". Make sure lineno stays up-to-date. |
3335 | 3750 | */ |
3336 | -PRIVATE void emit_code(out,rp,lemp,lineno) | |
3337 | -FILE *out; | |
3338 | -struct rule *rp; | |
3339 | -struct lemon *lemp; | |
3340 | -int *lineno; | |
3341 | -{ | |
3342 | - char *cp; | |
3343 | - int linecnt = 0; | |
3751 | +PRIVATE void emit_code( | |
3752 | + FILE *out, | |
3753 | + struct rule *rp, | |
3754 | + struct lemon *lemp, | |
3755 | + int *lineno | |
3756 | +){ | |
3757 | + const char *cp; | |
3758 | + | |
3759 | + /* Setup code prior to the #line directive */ | |
3760 | + if( rp->codePrefix && rp->codePrefix[0] ){ | |
3761 | + fprintf(out, "{%s", rp->codePrefix); | |
3762 | + for(cp=rp->codePrefix; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; } | |
3763 | + } | |
3344 | 3764 | |
3345 | 3765 | /* Generate code to do the reduce action */ |
3346 | 3766 | if( rp->code ){ |
3347 | - tplt_linedir(out,rp->line,lemp->filename); | |
3767 | + if( !lemp->nolinenosflag ){ | |
3768 | + (*lineno)++; | |
3769 | + tplt_linedir(out,rp->line,lemp->filename); | |
3770 | + } | |
3348 | 3771 | fprintf(out,"{%s",rp->code); |
3349 | - for(cp=rp->code; *cp; cp++){ | |
3350 | - if( *cp=='\n' ) linecnt++; | |
3351 | - } /* End loop */ | |
3352 | - (*lineno) += 3 + linecnt; | |
3353 | - fprintf(out,"}\n"); | |
3354 | - tplt_linedir(out,*lineno,lemp->outname); | |
3355 | - } /* End if( rp->code ) */ | |
3772 | + for(cp=rp->code; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; } | |
3773 | + fprintf(out,"}\n"); (*lineno)++; | |
3774 | + if( !lemp->nolinenosflag ){ | |
3775 | + (*lineno)++; | |
3776 | + tplt_linedir(out,*lineno,lemp->outname); | |
3777 | + } | |
3778 | + } | |
3779 | + | |
3780 | + /* Generate breakdown code that occurs after the #line directive */ | |
3781 | + if( rp->codeSuffix && rp->codeSuffix[0] ){ | |
3782 | + fprintf(out, "%s", rp->codeSuffix); | |
3783 | + for(cp=rp->codeSuffix; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; } | |
3784 | + } | |
3785 | + | |
3786 | + if( rp->codePrefix ){ | |
3787 | + fprintf(out, "}\n"); (*lineno)++; | |
3788 | + } | |
3356 | 3789 | |
3357 | 3790 | return; |
3358 | 3791 | } |
@@ -3364,33 +3797,37 @@ | ||
3364 | 3797 | ** union, also set the ".dtnum" field of every terminal and nonterminal |
3365 | 3798 | ** symbol. |
3366 | 3799 | */ |
3367 | -void print_stack_union(out,lemp,plineno,mhflag) | |
3368 | -FILE *out; /* The output stream */ | |
3369 | -struct lemon *lemp; /* The main info structure for this parser */ | |
3370 | -int *plineno; /* Pointer to the line number */ | |
3371 | -int mhflag; /* True if generating makeheaders output */ | |
3372 | -{ | |
3800 | +void print_stack_union( | |
3801 | + FILE *out, /* The output stream */ | |
3802 | + struct lemon *lemp, /* The main info structure for this parser */ | |
3803 | + int *plineno, /* Pointer to the line number */ | |
3804 | + int mhflag /* True if generating makeheaders output */ | |
3805 | +){ | |
3373 | 3806 | int lineno = *plineno; /* The line number of the output */ |
3374 | 3807 | char **types; /* A hash table of datatypes */ |
3375 | 3808 | int arraysize; /* Size of the "types" array */ |
3376 | 3809 | int maxdtlength; /* Maximum length of any ".datatype" field. */ |
3377 | 3810 | char *stddt; /* Standardized name for a datatype */ |
3378 | 3811 | int i,j; /* Loop counters */ |
3379 | - int hash; /* For hashing the name of a type */ | |
3380 | - char *name; /* Name of the parser */ | |
3812 | + unsigned hash; /* For hashing the name of a type */ | |
3813 | + const char *name; /* Name of the parser */ | |
3381 | 3814 | |
3382 | 3815 | /* Allocate and initialize types[] and allocate stddt[] */ |
3383 | 3816 | arraysize = lemp->nsymbol * 2; |
3384 | 3817 | types = (char**)calloc( arraysize, sizeof(char*) ); |
3818 | + if( types==0 ){ | |
3819 | + fprintf(stderr,"Out of memory.\n"); | |
3820 | + exit(1); | |
3821 | + } | |
3385 | 3822 | maxdtlength = 0; |
3386 | 3823 | if( lemp->vartype ){ |
3387 | - maxdtlength = (int)strlen(lemp->vartype); | |
3824 | + maxdtlength = lemonStrlen(lemp->vartype); | |
3388 | 3825 | } |
3389 | 3826 | for(i=0; i<lemp->nsymbol; i++){ |
3390 | 3827 | int len; |
3391 | 3828 | struct symbol *sp = lemp->symbols[i]; |
3392 | 3829 | if( sp->datatype==0 ) continue; |
3393 | - len = (int)strlen(sp->datatype); | |
3830 | + len = lemonStrlen(sp->datatype); | |
3394 | 3831 | if( len>maxdtlength ) maxdtlength = len; |
3395 | 3832 | } |
3396 | 3833 | stddt = (char*)malloc( maxdtlength*2 + 1 ); |
@@ -3419,10 +3856,14 @@ | ||
3419 | 3856 | cp = sp->datatype; |
3420 | 3857 | if( cp==0 ) cp = lemp->vartype; |
3421 | 3858 | j = 0; |
3422 | - while( isspace(*cp) ) cp++; | |
3859 | + while( ISSPACE(*cp) ) cp++; | |
3423 | 3860 | while( *cp ) stddt[j++] = *cp++; |
3424 | - while( j>0 && isspace(stddt[j-1]) ) j--; | |
3861 | + while( j>0 && ISSPACE(stddt[j-1]) ) j--; | |
3425 | 3862 | stddt[j] = 0; |
3863 | + if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){ | |
3864 | + sp->dtnum = 0; | |
3865 | + continue; | |
3866 | + } | |
3426 | 3867 | hash = 0; |
3427 | 3868 | for(j=0; stddt[j]; j++){ |
3428 | 3869 | hash = hash*53 + stddt[j]; |
@@ -3434,11 +3875,11 @@ | ||
3434 | 3875 | break; |
3435 | 3876 | } |
3436 | 3877 | hash++; |
3437 | - if( hash>=arraysize ) hash = 0; | |
3878 | + if( hash>=(unsigned)arraysize ) hash = 0; | |
3438 | 3879 | } |
3439 | 3880 | if( types[hash]==0 ){ |
3440 | 3881 | sp->dtnum = hash + 1; |
3441 | - types[hash] = (char*)malloc( strlen(stddt)+1 ); | |
3882 | + types[hash] = (char*)malloc( lemonStrlen(stddt)+1 ); | |
3442 | 3883 | if( types[hash]==0 ){ |
3443 | 3884 | fprintf(stderr,"Out of memory.\n"); |
3444 | 3885 | exit(1); |
@@ -3455,6 +3896,7 @@ | ||
3455 | 3896 | lemp->tokentype?lemp->tokentype:"void*"); lineno++; |
3456 | 3897 | if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } |
3457 | 3898 | fprintf(out,"typedef union {\n"); lineno++; |
3899 | + fprintf(out," int yyinit;\n"); lineno++; | |
3458 | 3900 | fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++; |
3459 | 3901 | for(i=0; i<arraysize; i++){ |
3460 | 3902 | if( types[i]==0 ) continue; |
@@ -3472,24 +3914,32 @@ | ||
3472 | 3914 | |
3473 | 3915 | /* |
3474 | 3916 | ** Return the name of a C datatype able to represent values between |
3475 | -** lwr and upr, inclusive. | |
3917 | +** lwr and upr, inclusive. If pnByte!=NULL then also write the sizeof | |
3918 | +** for that type (1, 2, or 4) into *pnByte. | |
3476 | 3919 | */ |
3477 | -static const char *minimum_size_type(int lwr, int upr){ | |
3920 | +static const char *minimum_size_type(int lwr, int upr, int *pnByte){ | |
3921 | + const char *zType = "int"; | |
3922 | + int nByte = 4; | |
3478 | 3923 | if( lwr>=0 ){ |
3479 | 3924 | if( upr<=255 ){ |
3480 | - return "unsigned char"; | |
3925 | + zType = "unsigned char"; | |
3926 | + nByte = 1; | |
3481 | 3927 | }else if( upr<65535 ){ |
3482 | - return "unsigned short int"; | |
3928 | + zType = "unsigned short int"; | |
3929 | + nByte = 2; | |
3483 | 3930 | }else{ |
3484 | - return "unsigned int"; | |
3931 | + zType = "unsigned int"; | |
3932 | + nByte = 4; | |
3485 | 3933 | } |
3486 | 3934 | }else if( lwr>=-127 && upr<=127 ){ |
3487 | - return "signed char"; | |
3935 | + zType = "signed char"; | |
3936 | + nByte = 1; | |
3488 | 3937 | }else if( lwr>=-32767 && upr<32767 ){ |
3489 | - return "short"; | |
3490 | - }else{ | |
3491 | - return "int"; | |
3492 | - } | |
3938 | + zType = "short"; | |
3939 | + nByte = 2; | |
3940 | + } | |
3941 | + if( pnByte ) *pnByte = nByte; | |
3942 | + return zType; | |
3493 | 3943 | } |
3494 | 3944 | |
3495 | 3945 | /* |
@@ -3502,6 +3952,7 @@ | ||
3502 | 3952 | struct state *stp; /* A pointer to a state */ |
3503 | 3953 | int isTkn; /* True to use tokens. False for non-terminals */ |
3504 | 3954 | int nAction; /* Number of actions */ |
3955 | + int iOrder; /* Original order of action sets */ | |
3505 | 3956 | }; |
3506 | 3957 | |
3507 | 3958 | /* |
@@ -3510,7 +3961,13 @@ | ||
3510 | 3961 | static int axset_compare(const void *a, const void *b){ |
3511 | 3962 | struct axset *p1 = (struct axset*)a; |
3512 | 3963 | struct axset *p2 = (struct axset*)b; |
3513 | - return p2->nAction - p1->nAction; | |
3964 | + int c; | |
3965 | + c = p2->nAction - p1->nAction; | |
3966 | + if( c==0 ){ | |
3967 | + c = p1->iOrder - p2->iOrder; | |
3968 | + } | |
3969 | + assert( c!=0 || p1==p2 ); | |
3970 | + return c; | |
3514 | 3971 | } |
3515 | 3972 | |
3516 | 3973 | /* |
@@ -3521,9 +3978,11 @@ | ||
3521 | 3978 | fprintf(out,"%s ::=", rp->lhs->name); |
3522 | 3979 | for(j=0; j<rp->nrhs; j++){ |
3523 | 3980 | struct symbol *sp = rp->rhs[j]; |
3524 | - fprintf(out," %s", sp->name); | |
3525 | - if( sp->type==MULTITERMINAL ){ | |
3981 | + if( sp->type!=MULTITERMINAL ){ | |
3982 | + fprintf(out," %s", sp->name); | |
3983 | + }else{ | |
3526 | 3984 | int k; |
3985 | + fprintf(out," %s", sp->subsym[0]->name); | |
3527 | 3986 | for(k=1; k<sp->nsubsym; k++){ |
3528 | 3987 | fprintf(out,"|%s",sp->subsym[k]->name); |
3529 | 3988 | } |
@@ -3533,10 +3992,10 @@ | ||
3533 | 3992 | |
3534 | 3993 | |
3535 | 3994 | /* Generate C source code for the parser */ |
3536 | -void ReportTable(lemp, mhflag) | |
3537 | -struct lemon *lemp; | |
3538 | -int mhflag; /* Output in makeheaders format if true */ | |
3539 | -{ | |
3995 | +void ReportTable( | |
3996 | + struct lemon *lemp, | |
3997 | + int mhflag /* Output in makeheaders format if true */ | |
3998 | +){ | |
3540 | 3999 | FILE *out, *in; |
3541 | 4000 | char line[LINESIZE]; |
3542 | 4001 | int lineno; |
@@ -3544,8 +4003,10 @@ | ||
3544 | 4003 | struct action *ap; |
3545 | 4004 | struct rule *rp; |
3546 | 4005 | struct acttab *pActtab; |
3547 | - int i, j, n; | |
3548 | - char *name; | |
4006 | + int i, j, n, sz; | |
4007 | + int szActionType; /* sizeof(YYACTIONTYPE) */ | |
4008 | + int szCodeType; /* sizeof(YYCODETYPE) */ | |
4009 | + const char *name; | |
3549 | 4010 | int mnTknOfst, mxTknOfst; |
3550 | 4011 | int mnNtOfst, mxNtOfst; |
3551 | 4012 | struct axset *ax; |
@@ -3561,7 +4022,7 @@ | ||
3561 | 4022 | tplt_xfer(lemp->name,in,out,&lineno); |
3562 | 4023 | |
3563 | 4024 | /* Generate the include code, if any */ |
3564 | - tplt_print(out,lemp,lemp->include,lemp->includeln,&lineno); | |
4025 | + tplt_print(out,lemp,lemp->include,&lineno); | |
3565 | 4026 | if( mhflag ){ |
3566 | 4027 | char *name = file_makename(lemp, ".h"); |
3567 | 4028 | fprintf(out,"#include \"%s\"\n", name); lineno++; |
@@ -3571,7 +4032,7 @@ | ||
3571 | 4032 | |
3572 | 4033 | /* Generate #defines for all tokens */ |
3573 | 4034 | if( mhflag ){ |
3574 | - char *prefix; | |
4035 | + const char *prefix; | |
3575 | 4036 | fprintf(out,"#if INTERFACE\n"); lineno++; |
3576 | 4037 | if( lemp->tokenprefix ) prefix = lemp->tokenprefix; |
3577 | 4038 | else prefix = ""; |
@@ -3585,10 +4046,10 @@ | ||
3585 | 4046 | |
3586 | 4047 | /* Generate the defines */ |
3587 | 4048 | fprintf(out,"#define YYCODETYPE %s\n", |
3588 | - minimum_size_type(0, lemp->nsymbol+5)); lineno++; | |
4049 | + minimum_size_type(0, lemp->nsymbol+1, &szCodeType)); lineno++; | |
3589 | 4050 | fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; |
3590 | 4051 | fprintf(out,"#define YYACTIONTYPE %s\n", |
3591 | - minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++; | |
4052 | + minimum_size_type(0,lemp->nstate+lemp->nrule*2+5,&szActionType)); lineno++; | |
3592 | 4053 | if( lemp->wildcard ){ |
3593 | 4054 | fprintf(out,"#define YYWILDCARD %d\n", |
3594 | 4055 | lemp->wildcard->index); lineno++; |
@@ -3607,9 +4068,9 @@ | ||
3607 | 4068 | name = lemp->name ? lemp->name : "Parse"; |
3608 | 4069 | if( lemp->arg && lemp->arg[0] ){ |
3609 | 4070 | size_t i; |
3610 | - i = strlen(lemp->arg); | |
3611 | - while( i>=1 && isspace(lemp->arg[i-1]) ) i--; | |
3612 | - while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; | |
4071 | + i = lemonStrlen(lemp->arg); | |
4072 | + while( i>=1 && ISSPACE(lemp->arg[i-1]) ) i--; | |
4073 | + while( i>=1 && (ISALNUM(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; | |
3613 | 4074 | fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++; |
3614 | 4075 | fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg); lineno++; |
3615 | 4076 | fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n", |
@@ -3625,36 +4086,24 @@ | ||
3625 | 4086 | if( mhflag ){ |
3626 | 4087 | fprintf(out,"#endif\n"); lineno++; |
3627 | 4088 | } |
3628 | - fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++; | |
3629 | - fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; | |
3630 | 4089 | if( lemp->errsym->useCnt ){ |
3631 | - fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; | |
3632 | - fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; | |
4090 | + fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; | |
4091 | + fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; | |
3633 | 4092 | } |
3634 | 4093 | if( lemp->has_fallback ){ |
3635 | 4094 | fprintf(out,"#define YYFALLBACK 1\n"); lineno++; |
3636 | 4095 | } |
3637 | - tplt_xfer(lemp->name,in,out,&lineno); | |
3638 | - | |
3639 | - /* Generate the action table and its associates: | |
3640 | - ** | |
3641 | - ** yy_action[] A single table containing all actions. | |
3642 | - ** yy_lookahead[] A table containing the lookahead for each entry in | |
3643 | - ** yy_action. Used to detect hash collisions. | |
3644 | - ** yy_shift_ofst[] For each state, the offset into yy_action for | |
3645 | - ** shifting terminals. | |
3646 | - ** yy_reduce_ofst[] For each state, the offset into yy_action for | |
3647 | - ** shifting non-terminals after a reduce. | |
3648 | - ** yy_default[] Default action for each state. | |
4096 | + | |
4097 | + /* Compute the action table, but do not output it yet. The action | |
4098 | + ** table must be computed before generating the YYNSTATE macro because | |
4099 | + ** we need to know how many states can be eliminated. | |
3649 | 4100 | */ |
3650 | - | |
3651 | - /* Compute the actions on all states and count them up */ | |
3652 | - ax = calloc(lemp->nstate*2 , sizeof(ax[0])); | |
4101 | + ax = (struct axset *) calloc(lemp->nxstate*2 , sizeof(ax[0])); | |
3653 | 4102 | if( ax==0 ){ |
3654 | 4103 | fprintf(stderr,"malloc failed\n"); |
3655 | 4104 | exit(1); |
3656 | 4105 | } |
3657 | - for(i=0; i<lemp->nstate; i++){ | |
4106 | + for(i=0; i<lemp->nxstate; i++){ | |
3658 | 4107 | stp = lemp->sorted[i]; |
3659 | 4108 | ax[i*2].stp = stp; |
3660 | 4109 | ax[i*2].isTkn = 1; |
@@ -3665,14 +4114,12 @@ | ||
3665 | 4114 | } |
3666 | 4115 | mxTknOfst = mnTknOfst = 0; |
3667 | 4116 | mxNtOfst = mnNtOfst = 0; |
3668 | - | |
3669 | - /* Compute the action table. In order to try to keep the size of the | |
3670 | - ** action table to a minimum, the heuristic of placing the largest action | |
3671 | - ** sets first is used. | |
3672 | - */ | |
3673 | - qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare); | |
4117 | + /* In an effort to minimize the action table size, use the heuristic | |
4118 | + ** of placing the largest action sets first */ | |
4119 | + for(i=0; i<lemp->nxstate*2; i++) ax[i].iOrder = i; | |
4120 | + qsort(ax, lemp->nxstate*2, sizeof(ax[0]), axset_compare); | |
3674 | 4121 | pActtab = acttab_alloc(); |
3675 | - for(i=0; i<lemp->nstate*2 && ax[i].nAction>0; i++){ | |
4122 | + for(i=0; i<lemp->nxstate*2 && ax[i].nAction>0; i++){ | |
3676 | 4123 | stp = ax[i].stp; |
3677 | 4124 | if( ax[i].isTkn ){ |
3678 | 4125 | for(ap=stp->ap; ap; ap=ap->next){ |
@@ -3698,12 +4145,67 @@ | ||
3698 | 4145 | if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst; |
3699 | 4146 | if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst; |
3700 | 4147 | } |
4148 | +#if 0 /* Uncomment for a trace of how the yy_action[] table fills out */ | |
4149 | + { int jj, nn; | |
4150 | + for(jj=nn=0; jj<pActtab->nAction; jj++){ | |
4151 | + if( pActtab->aAction[jj].action<0 ) nn++; | |
4152 | + } | |
4153 | + printf("%4d: State %3d %s n: %2d size: %5d freespace: %d\n", | |
4154 | + i, stp->statenum, ax[i].isTkn ? "Token" : "Var ", | |
4155 | + ax[i].nAction, pActtab->nAction, nn); | |
4156 | + } | |
4157 | +#endif | |
3701 | 4158 | } |
3702 | 4159 | free(ax); |
3703 | 4160 | |
4161 | +#if 0 | |
4162 | + /* Mark rules that are actually used for reduce actions after all | |
4163 | + ** optimizations have been applied | |
4164 | + */ | |
4165 | + for(rp=lemp->rule; rp; rp=rp->next) rp->doesReduce = LEMON_FALSE; | |
4166 | + for(i=0; i<lemp->nxstate; i++){ | |
4167 | + struct action *ap; | |
4168 | + for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ | |
4169 | + if( ap->type==REDUCE || ap->type==SHIFTREDUCE ){ | |
4170 | + ap->x.rp->doesReduce = i; | |
4171 | + } | |
4172 | + } | |
4173 | + } | |
4174 | +#endif | |
4175 | + | |
4176 | + /* Finish rendering the constants now that the action table has | |
4177 | + ** been computed */ | |
4178 | + fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; | |
4179 | + fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; | |
4180 | + fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++; | |
4181 | + fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",lemp->nstate); lineno++; | |
4182 | + i = lemp->nstate + lemp->nrule; | |
4183 | + fprintf(out,"#define YY_MAX_SHIFTREDUCE %d\n", i-1); lineno++; | |
4184 | + fprintf(out,"#define YY_MIN_REDUCE %d\n", i); lineno++; | |
4185 | + i = lemp->nstate + lemp->nrule*2; | |
4186 | + fprintf(out,"#define YY_MAX_REDUCE %d\n", i-1); lineno++; | |
4187 | + fprintf(out,"#define YY_ERROR_ACTION %d\n", i); lineno++; | |
4188 | + fprintf(out,"#define YY_ACCEPT_ACTION %d\n", i+1); lineno++; | |
4189 | + fprintf(out,"#define YY_NO_ACTION %d\n", i+2); lineno++; | |
4190 | + tplt_xfer(lemp->name,in,out,&lineno); | |
4191 | + | |
4192 | + /* Now output the action table and its associates: | |
4193 | + ** | |
4194 | + ** yy_action[] A single table containing all actions. | |
4195 | + ** yy_lookahead[] A table containing the lookahead for each entry in | |
4196 | + ** yy_action. Used to detect hash collisions. | |
4197 | + ** yy_shift_ofst[] For each state, the offset into yy_action for | |
4198 | + ** shifting terminals. | |
4199 | + ** yy_reduce_ofst[] For each state, the offset into yy_action for | |
4200 | + ** shifting non-terminals after a reduce. | |
4201 | + ** yy_default[] Default action for each state. | |
4202 | + */ | |
4203 | + | |
3704 | 4204 | /* Output the yy_action table */ |
4205 | + lemp->nactiontab = n = acttab_size(pActtab); | |
4206 | + lemp->tablesize += n*szActionType; | |
4207 | + fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++; | |
3705 | 4208 | fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; |
3706 | - n = acttab_size(pActtab); | |
3707 | 4209 | for(i=j=0; i<n; i++){ |
3708 | 4210 | int action = acttab_yyaction(pActtab, i); |
3709 | 4211 | if( action<0 ) action = lemp->nstate + lemp->nrule + 2; |
@@ -3719,6 +4221,7 @@ | ||
3719 | 4221 | fprintf(out, "};\n"); lineno++; |
3720 | 4222 | |
3721 | 4223 | /* Output the yy_lookahead table */ |
4224 | + lemp->tablesize += n*szCodeType; | |
3722 | 4225 | fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; |
3723 | 4226 | for(i=j=0; i<n; i++){ |
3724 | 4227 | int la = acttab_yylookahead(pActtab, i); |
@@ -3735,17 +4238,21 @@ | ||
3735 | 4238 | fprintf(out, "};\n"); lineno++; |
3736 | 4239 | |
3737 | 4240 | /* Output the yy_shift_ofst[] table */ |
3738 | - fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; | |
3739 | - n = lemp->nstate; | |
4241 | + n = lemp->nxstate; | |
3740 | 4242 | while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; |
3741 | - fprintf(out, "#define YY_SHIFT_MAX %d\n", n-1); lineno++; | |
4243 | + fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", lemp->nactiontab); lineno++; | |
4244 | + fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; | |
4245 | + fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; | |
4246 | + fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; | |
3742 | 4247 | fprintf(out, "static const %s yy_shift_ofst[] = {\n", |
3743 | - minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++; | |
4248 | + minimum_size_type(mnTknOfst, lemp->nterminal+lemp->nactiontab, &sz)); | |
4249 | + lineno++; | |
4250 | + lemp->tablesize += n*sz; | |
3744 | 4251 | for(i=j=0; i<n; i++){ |
3745 | 4252 | int ofst; |
3746 | 4253 | stp = lemp->sorted[i]; |
3747 | 4254 | ofst = stp->iTknOfst; |
3748 | - if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; | |
4255 | + if( ofst==NO_OFFSET ) ofst = lemp->nactiontab; | |
3749 | 4256 | if( j==0 ) fprintf(out," /* %5d */ ", i); |
3750 | 4257 | fprintf(out, " %4d,", ofst); |
3751 | 4258 | if( j==9 || i==n-1 ){ |
@@ -3759,11 +4266,14 @@ | ||
3759 | 4266 | |
3760 | 4267 | /* Output the yy_reduce_ofst[] table */ |
3761 | 4268 | fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; |
3762 | - n = lemp->nstate; | |
4269 | + n = lemp->nxstate; | |
3763 | 4270 | while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; |
3764 | - fprintf(out, "#define YY_REDUCE_MAX %d\n", n-1); lineno++; | |
4271 | + fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++; | |
4272 | + fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++; | |
4273 | + fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++; | |
3765 | 4274 | fprintf(out, "static const %s yy_reduce_ofst[] = {\n", |
3766 | - minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; | |
4275 | + minimum_size_type(mnNtOfst-1, mxNtOfst, &sz)); lineno++; | |
4276 | + lemp->tablesize += n*sz; | |
3767 | 4277 | for(i=j=0; i<n; i++){ |
3768 | 4278 | int ofst; |
3769 | 4279 | stp = lemp->sorted[i]; |
@@ -3782,11 +4292,12 @@ | ||
3782 | 4292 | |
3783 | 4293 | /* Output the default action table */ |
3784 | 4294 | fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; |
3785 | - n = lemp->nstate; | |
4295 | + n = lemp->nxstate; | |
4296 | + lemp->tablesize += n*szActionType; | |
3786 | 4297 | for(i=j=0; i<n; i++){ |
3787 | 4298 | stp = lemp->sorted[i]; |
3788 | 4299 | if( j==0 ) fprintf(out," /* %5d */ ", i); |
3789 | - fprintf(out, " %4d,", stp->iDflt); | |
4300 | + fprintf(out, " %4d,", stp->iDfltReduce+lemp->nstate+lemp->nrule); | |
3790 | 4301 | if( j==9 || i==n-1 ){ |
3791 | 4302 | fprintf(out, "\n"); lineno++; |
3792 | 4303 | j = 0; |
@@ -3800,7 +4311,10 @@ | ||
3800 | 4311 | /* Generate the table of fallback tokens. |
3801 | 4312 | */ |
3802 | 4313 | if( lemp->has_fallback ){ |
3803 | - for(i=0; i<lemp->nterminal; i++){ | |
4314 | + int mx = lemp->nterminal - 1; | |
4315 | + while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } | |
4316 | + lemp->tablesize += (mx+1)*szCodeType; | |
4317 | + for(i=0; i<=mx; i++){ | |
3804 | 4318 | struct symbol *p = lemp->symbols[i]; |
3805 | 4319 | if( p->fallback==0 ){ |
3806 | 4320 | fprintf(out, " 0, /* %10s => nothing */\n", p->name); |
@@ -3824,11 +4338,11 @@ | ||
3824 | 4338 | tplt_xfer(lemp->name,in,out,&lineno); |
3825 | 4339 | |
3826 | 4340 | /* Generate a table containing a text string that describes every |
3827 | - ** rule in the rule set of the grammer. This information is used | |
4341 | + ** rule in the rule set of the grammar. This information is used | |
3828 | 4342 | ** when tracing REDUCE actions. |
3829 | 4343 | */ |
3830 | 4344 | for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ |
3831 | - assert( rp->index==i ); | |
4345 | + assert( rp->iRule==i ); | |
3832 | 4346 | fprintf(out," /* %3d */ \"", i); |
3833 | 4347 | writeRuleText(out, rp); |
3834 | 4348 | fprintf(out,"\",\n"); lineno++; |
@@ -3840,11 +4354,15 @@ | ||
3840 | 4354 | ** (In other words, generate the %destructor actions) |
3841 | 4355 | */ |
3842 | 4356 | if( lemp->tokendest ){ |
4357 | + int once = 1; | |
3843 | 4358 | for(i=0; i<lemp->nsymbol; i++){ |
3844 | 4359 | struct symbol *sp = lemp->symbols[i]; |
3845 | 4360 | if( sp==0 || sp->type!=TERMINAL ) continue; |
3846 | - fprintf(out," case %d: /* %s */\n", | |
3847 | - sp->index, sp->name); lineno++; | |
4361 | + if( once ){ | |
4362 | + fprintf(out, " /* TERMINAL Destructor */\n"); lineno++; | |
4363 | + once = 0; | |
4364 | + } | |
4365 | + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; | |
3848 | 4366 | } |
3849 | 4367 | for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++); |
3850 | 4368 | if( i<lemp->nsymbol ){ |
@@ -3854,24 +4372,28 @@ | ||
3854 | 4372 | } |
3855 | 4373 | if( lemp->vardest ){ |
3856 | 4374 | struct symbol *dflt_sp = 0; |
4375 | + int once = 1; | |
3857 | 4376 | for(i=0; i<lemp->nsymbol; i++){ |
3858 | 4377 | struct symbol *sp = lemp->symbols[i]; |
3859 | 4378 | if( sp==0 || sp->type==TERMINAL || |
3860 | 4379 | sp->index<=0 || sp->destructor!=0 ) continue; |
3861 | - fprintf(out," case %d: /* %s */\n", | |
3862 | - sp->index, sp->name); lineno++; | |
4380 | + if( once ){ | |
4381 | + fprintf(out, " /* Default NON-TERMINAL Destructor */\n"); lineno++; | |
4382 | + once = 0; | |
4383 | + } | |
4384 | + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; | |
3863 | 4385 | dflt_sp = sp; |
3864 | 4386 | } |
3865 | 4387 | if( dflt_sp!=0 ){ |
3866 | 4388 | emit_destructor_code(out,dflt_sp,lemp,&lineno); |
3867 | - fprintf(out," break;\n"); lineno++; | |
3868 | 4389 | } |
4390 | + fprintf(out," break;\n"); lineno++; | |
3869 | 4391 | } |
3870 | 4392 | for(i=0; i<lemp->nsymbol; i++){ |
3871 | 4393 | struct symbol *sp = lemp->symbols[i]; |
3872 | 4394 | if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; |
3873 | - fprintf(out," case %d: /* %s */\n", | |
3874 | - sp->index, sp->name); lineno++; | |
4395 | + if( sp->destLineno<0 ) continue; /* Already emitted */ | |
4396 | + fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; | |
3875 | 4397 | |
3876 | 4398 | /* Combine duplicate destructors into a single case */ |
3877 | 4399 | for(j=i+1; j<lemp->nsymbol; j++){ |
@@ -3881,7 +4403,7 @@ | ||
3881 | 4403 | && strcmp(sp->destructor,sp2->destructor)==0 ){ |
3882 | 4404 | fprintf(out," case %d: /* %s */\n", |
3883 | 4405 | sp2->index, sp2->name); lineno++; |
3884 | - sp2->destructor = 0; | |
4406 | + sp2->destLineno = -1; /* Avoid emitting this destructor again */ | |
3885 | 4407 | } |
3886 | 4408 | } |
3887 | 4409 |
@@ -3891,7 +4413,7 @@ | ||
3891 | 4413 | tplt_xfer(lemp->name,in,out,&lineno); |
3892 | 4414 | |
3893 | 4415 | /* Generate code which executes whenever the parser stack overflows */ |
3894 | - tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno); | |
4416 | + tplt_print(out,lemp,lemp->overflow,&lineno); | |
3895 | 4417 | tplt_xfer(lemp->name,in,out,&lineno); |
3896 | 4418 | |
3897 | 4419 | /* Generate the table of rule information |
@@ -3905,54 +4427,85 @@ | ||
3905 | 4427 | tplt_xfer(lemp->name,in,out,&lineno); |
3906 | 4428 | |
3907 | 4429 | /* Generate code which executes during each REDUCE action */ |
3908 | - for(rp=lemp->rule; rp; rp=rp->next){ | |
3909 | - translate_code(lemp, rp); | |
3910 | - } | |
4430 | + i = 0; | |
3911 | 4431 | for(rp=lemp->rule; rp; rp=rp->next){ |
3912 | - struct rule *rp2; | |
3913 | - if( rp->code==0 ) continue; | |
3914 | - fprintf(out," case %d: /* ",rp->index); | |
4432 | + i += translate_code(lemp, rp); | |
4433 | + } | |
4434 | + if( i ){ | |
4435 | + fprintf(out," YYMINORTYPE yylhsminor;\n"); lineno++; | |
4436 | + } | |
4437 | + /* First output rules other than the default: rule */ | |
4438 | + for(rp=lemp->rule; rp; rp=rp->next){ | |
4439 | + struct rule *rp2; /* Other rules with the same action */ | |
4440 | + if( rp->codeEmitted ) continue; | |
4441 | + if( rp->noCode ){ | |
4442 | + /* No C code actions, so this will be part of the "default:" rule */ | |
4443 | + continue; | |
4444 | + } | |
4445 | + fprintf(out," case %d: /* ",rp->iRule); | |
3915 | 4446 | writeRuleText(out, rp); |
3916 | - fprintf(out, " */\n"); lineno++; | |
4447 | + fprintf(out," */\n"); lineno++; | |
3917 | 4448 | for(rp2=rp->next; rp2; rp2=rp2->next){ |
3918 | - if( rp2->code==rp->code ){ | |
3919 | - fprintf(out," case %d: /*",rp2->index); | |
4449 | + if( rp2->code==rp->code && rp2->codePrefix==rp->codePrefix | |
4450 | + && rp2->codeSuffix == rp->codeSuffix ){ | |
4451 | + fprintf(out," case %d: /*",rp2->iRule); | |
3920 | 4452 | writeRuleText(out, rp2); |
3921 | - fprintf(out," */\n"); lineno++; | |
3922 | - rp2->code = 0; | |
4453 | + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp2->iRule); lineno++; | |
4454 | + rp2->codeEmitted = 1; | |
3923 | 4455 | } |
3924 | 4456 | } |
3925 | 4457 | emit_code(out,rp,lemp,&lineno); |
3926 | 4458 | fprintf(out," break;\n"); lineno++; |
3927 | - } | |
4459 | + rp->codeEmitted = 1; | |
4460 | + } | |
4461 | + /* Finally, output the default: rule. We choose as the default: all | |
4462 | + ** empty actions. */ | |
4463 | + fprintf(out," default:\n"); lineno++; | |
4464 | + for(rp=lemp->rule; rp; rp=rp->next){ | |
4465 | + if( rp->codeEmitted ) continue; | |
4466 | + assert( rp->noCode ); | |
4467 | + fprintf(out," /* (%d) ", rp->iRule); | |
4468 | + writeRuleText(out, rp); | |
4469 | +#if 0 | |
4470 | + if( rp->doesReduce ){ | |
4471 | +#endif | |
4472 | + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++; | |
4473 | +#if 0 | |
4474 | + }else{ | |
4475 | + fprintf(out, " (OPTIMIZED OUT) */ assert(yyruleno!=%d);\n", | |
4476 | + rp->iRule); lineno++; | |
4477 | + } | |
4478 | +#endif | |
4479 | + } | |
4480 | + fprintf(out," break;\n"); lineno++; | |
3928 | 4481 | tplt_xfer(lemp->name,in,out,&lineno); |
3929 | 4482 | |
3930 | 4483 | /* Generate code which executes if a parse fails */ |
3931 | - tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno); | |
4484 | + tplt_print(out,lemp,lemp->failure,&lineno); | |
3932 | 4485 | tplt_xfer(lemp->name,in,out,&lineno); |
3933 | 4486 | |
3934 | 4487 | /* Generate code which executes when a syntax error occurs */ |
3935 | - tplt_print(out,lemp,lemp->error,lemp->errorln,&lineno); | |
4488 | + tplt_print(out,lemp,lemp->error,&lineno); | |
3936 | 4489 | tplt_xfer(lemp->name,in,out,&lineno); |
3937 | 4490 | |
3938 | 4491 | /* Generate code which executes when the parser accepts its input */ |
3939 | - tplt_print(out,lemp,lemp->accept,lemp->acceptln,&lineno); | |
4492 | + tplt_print(out,lemp,lemp->accept,&lineno); | |
3940 | 4493 | tplt_xfer(lemp->name,in,out,&lineno); |
3941 | 4494 | |
3942 | 4495 | /* Append any addition code the user desires */ |
3943 | - tplt_print(out,lemp,lemp->extracode,lemp->extracodeln,&lineno); | |
3944 | - | |
4496 | + tplt_print(out,lemp,lemp->extracode,&lineno); | |
4497 | + | |
4498 | + acttab_free(&pActtab); | |
3945 | 4499 | fclose(in); |
3946 | 4500 | fclose(out); |
3947 | 4501 | return; |
3948 | 4502 | } |
3949 | 4503 | |
3950 | 4504 | /* Generate a header file for the parser */ |
3951 | -void ReportHeader(lemp) | |
3952 | -struct lemon *lemp; | |
4505 | +void ReportHeader(struct lemon *lemp) | |
3953 | 4506 | { |
3954 | 4507 | FILE *out, *in; |
3955 | - char *prefix; | |
4508 | + const char *prefix; | |
3956 | 4509 | char line[LINESIZE]; |
3957 | 4510 | char pattern[LINESIZE]; |
3958 | 4511 | int i; |
@@ -3961,12 +4514,15 @@ | ||
3961 | 4514 | else prefix = ""; |
3962 | 4515 | in = file_open(lemp,".h","rb"); |
3963 | 4516 | if( in ){ |
4517 | + int nextChar; | |
3964 | 4518 | for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){ |
3965 | - sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); | |
4519 | + sprintf(pattern,"#define %s%-30s %2d\n", | |
4520 | + prefix,lemp->symbols[i]->name,i); | |
3966 | 4521 | if( strcmp(line,pattern) ) break; |
3967 | 4522 | } |
4523 | + nextChar = fgetc(in); | |
3968 | 4524 | fclose(in); |
3969 | - if( i==lemp->nterminal ){ | |
4525 | + if( i==lemp->nterminal && nextChar==EOF ){ | |
3970 | 4526 | /* No change in the file. Don't rewrite it. */ |
3971 | 4527 | /* (not the best idea if you use make tools that check the date! */ |
3972 | 4528 | /*return;*/ |
@@ -3975,7 +4531,7 @@ | ||
3975 | 4531 | out = file_open(lemp,".h","wb"); |
3976 | 4532 | if( out ){ |
3977 | 4533 | for(i=1; i<lemp->nterminal; i++){ |
3978 | - fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); | |
4534 | + fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i); | |
3979 | 4535 | } |
3980 | 4536 | fclose(out); |
3981 | 4537 | } |
@@ -3989,11 +4545,10 @@ | ||
3989 | 4545 | ** it the default. Except, there is no default if the wildcard token |
3990 | 4546 | ** is a possible look-ahead. |
3991 | 4547 | */ |
3992 | -void CompressTables(lemp) | |
3993 | -struct lemon *lemp; | |
4548 | +void CompressTables(struct lemon *lemp) | |
3994 | 4549 | { |
3995 | 4550 | struct state *stp; |
3996 | - struct action *ap, *ap2; | |
4551 | + struct action *ap, *ap2, *nextap; | |
3997 | 4552 | struct rule *rp, *rp2, *rbest; |
3998 | 4553 | int nbest, n; |
3999 | 4554 | int i; |
@@ -4028,7 +4583,7 @@ | ||
4028 | 4583 | |
4029 | 4584 | /* Do not make a default if the number of rules to default |
4030 | 4585 | ** is not at least 1 or if the wildcard token is a possbile |
4031 | - ** lookahed. | |
4586 | + ** lookahead. | |
4032 | 4587 | */ |
4033 | 4588 | if( nbest<1 || usesWildcard ) continue; |
4034 | 4589 |
@@ -4043,6 +4598,62 @@ | ||
4043 | 4598 | if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED; |
4044 | 4599 | } |
4045 | 4600 | stp->ap = Action_sort(stp->ap); |
4601 | + | |
4602 | + for(ap=stp->ap; ap; ap=ap->next){ | |
4603 | + if( ap->type==SHIFT ) break; | |
4604 | + if( ap->type==REDUCE && ap->x.rp!=rbest ) break; | |
4605 | + } | |
4606 | + if( ap==0 ){ | |
4607 | + stp->autoReduce = 1; | |
4608 | + stp->pDfltReduce = rbest; | |
4609 | + } | |
4610 | + } | |
4611 | + | |
4612 | + /* Make a second pass over all states and actions. Convert | |
4613 | + ** every action that is a SHIFT to an autoReduce state into | |
4614 | + ** a SHIFTREDUCE action. | |
4615 | + */ | |
4616 | + for(i=0; i<lemp->nstate; i++){ | |
4617 | + stp = lemp->sorted[i]; | |
4618 | + for(ap=stp->ap; ap; ap=ap->next){ | |
4619 | + struct state *pNextState; | |
4620 | + if( ap->type!=SHIFT ) continue; | |
4621 | + pNextState = ap->x.stp; | |
4622 | + if( pNextState->autoReduce && pNextState->pDfltReduce!=0 ){ | |
4623 | + ap->type = SHIFTREDUCE; | |
4624 | + ap->x.rp = pNextState->pDfltReduce; | |
4625 | + } | |
4626 | + } | |
4627 | + } | |
4628 | + | |
4629 | + /* If a SHIFTREDUCE action specifies a rule that has a single RHS term | |
4630 | + ** (meaning that the SHIFTREDUCE will land back in the state where it | |
4631 | + ** started) and if there is no C-code associated with the reduce action, | |
4632 | + ** then we can go ahead and convert the action to be the same as the | |
4633 | + ** action for the RHS of the rule. | |
4634 | + */ | |
4635 | + for(i=0; i<lemp->nstate; i++){ | |
4636 | + stp = lemp->sorted[i]; | |
4637 | + for(ap=stp->ap; ap; ap=nextap){ | |
4638 | + nextap = ap->next; | |
4639 | + if( ap->type!=SHIFTREDUCE ) continue; | |
4640 | + rp = ap->x.rp; | |
4641 | + if( rp->noCode==0 ) continue; | |
4642 | + if( rp->nrhs!=1 ) continue; | |
4643 | +#if 1 | |
4644 | + /* Only apply this optimization to non-terminals. It would be OK to | |
4645 | + ** apply it to terminal symbols too, but that makes the parser tables | |
4646 | + ** larger. */ | |
4647 | + if( ap->sp->index<lemp->nterminal ) continue; | |
4648 | +#endif | |
4649 | + /* If we reach this point, it means the optimization can be applied */ | |
4650 | + nextap = ap; | |
4651 | + for(ap2=stp->ap; ap2 && (ap2==ap || ap2->sp!=rp->lhs); ap2=ap2->next){} | |
4652 | + assert( ap2!=0 ); | |
4653 | + ap->spOpt = ap2->sp; | |
4654 | + ap->type = ap2->type; | |
4655 | + ap->x = ap2->x; | |
4656 | + } | |
4046 | 4657 | } |
4047 | 4658 | } |
4048 | 4659 |
@@ -4061,7 +4672,11 @@ | ||
4061 | 4672 | n = pB->nNtAct - pA->nNtAct; |
4062 | 4673 | if( n==0 ){ |
4063 | 4674 | n = pB->nTknAct - pA->nTknAct; |
4064 | - } | |
4675 | + if( n==0 ){ | |
4676 | + n = pB->statenum - pA->statenum; | |
4677 | + } | |
4678 | + } | |
4679 | + assert( n!=0 ); | |
4065 | 4680 | return n; |
4066 | 4681 | } |
4067 | 4682 |
@@ -4070,8 +4685,7 @@ | ||
4070 | 4685 | ** Renumber and resort states so that states with fewer choices |
4071 | 4686 | ** occur at the end. Except, keep state 0 as the first state. |
4072 | 4687 | */ |
4073 | -void ResortStates(lemp) | |
4074 | -struct lemon *lemp; | |
4688 | +void ResortStates(struct lemon *lemp) | |
4075 | 4689 | { |
4076 | 4690 | int i; |
4077 | 4691 | struct state *stp; |
@@ -4080,17 +4694,19 @@ | ||
4080 | 4694 | for(i=0; i<lemp->nstate; i++){ |
4081 | 4695 | stp = lemp->sorted[i]; |
4082 | 4696 | stp->nTknAct = stp->nNtAct = 0; |
4083 | - stp->iDflt = lemp->nstate + lemp->nrule; | |
4697 | + stp->iDfltReduce = lemp->nrule; /* Init dflt action to "syntax error" */ | |
4084 | 4698 | stp->iTknOfst = NO_OFFSET; |
4085 | 4699 | stp->iNtOfst = NO_OFFSET; |
4086 | 4700 | for(ap=stp->ap; ap; ap=ap->next){ |
4087 | - if( compute_action(lemp,ap)>=0 ){ | |
4701 | + int iAction = compute_action(lemp,ap); | |
4702 | + if( iAction>=0 ){ | |
4088 | 4703 | if( ap->sp->index<lemp->nterminal ){ |
4089 | 4704 | stp->nTknAct++; |
4090 | 4705 | }else if( ap->sp->index<lemp->nsymbol ){ |
4091 | 4706 | stp->nNtAct++; |
4092 | 4707 | }else{ |
4093 | - stp->iDflt = compute_action(lemp, ap); | |
4708 | + assert( stp->autoReduce==0 || stp->pDfltReduce==ap->x.rp ); | |
4709 | + stp->iDfltReduce = iAction - lemp->nstate - lemp->nrule; | |
4094 | 4710 | } |
4095 | 4711 | } |
4096 | 4712 | } |
@@ -4100,6 +4716,10 @@ | ||
4100 | 4716 | for(i=0; i<lemp->nstate; i++){ |
4101 | 4717 | lemp->sorted[i]->statenum = i; |
4102 | 4718 | } |
4719 | + lemp->nxstate = lemp->nstate; | |
4720 | + while( lemp->nxstate>1 && lemp->sorted[lemp->nxstate-1]->autoReduce ){ | |
4721 | + lemp->nxstate--; | |
4722 | + } | |
4103 | 4723 | } |
4104 | 4724 | |
4105 | 4725 |
@@ -4111,8 +4731,7 @@ | ||
4111 | 4731 | static int size = 0; |
4112 | 4732 | |
4113 | 4733 | /* Set the set size */ |
4114 | -void SetSize(n) | |
4115 | -int n; | |
4734 | +void SetSize(int n) | |
4116 | 4735 | { |
4117 | 4736 | size = n+1; |
4118 | 4737 | } |
@@ -4129,17 +4748,14 @@ | ||
4129 | 4748 | } |
4130 | 4749 | |
4131 | 4750 | /* Deallocate a set */ |
4132 | -void SetFree(s) | |
4133 | -char *s; | |
4751 | +void SetFree(char *s) | |
4134 | 4752 | { |
4135 | 4753 | free(s); |
4136 | 4754 | } |
4137 | 4755 | |
4138 | 4756 | /* Add a new element to the set. Return TRUE if the element was added |
4139 | 4757 | ** and FALSE if it was already there. */ |
4140 | -int SetAdd(s,e) | |
4141 | -char *s; | |
4142 | -int e; | |
4758 | +int SetAdd(char *s, int e) | |
4143 | 4759 | { |
4144 | 4760 | int rv; |
4145 | 4761 | assert( e>=0 && e<size ); |
@@ -4149,9 +4765,7 @@ | ||
4149 | 4765 | } |
4150 | 4766 | |
4151 | 4767 | /* Add every element of s2 to s1. Return TRUE if s1 changes. */ |
4152 | -int SetUnion(s1,s2) | |
4153 | -char *s1; | |
4154 | -char *s2; | |
4768 | +int SetUnion(char *s1, char *s2) | |
4155 | 4769 | { |
4156 | 4770 | int i, progress; |
4157 | 4771 | progress = 0; |
@@ -4177,11 +4791,10 @@ | ||
4177 | 4791 | ** Code for processing tables in the LEMON parser generator. |
4178 | 4792 | */ |
4179 | 4793 | |
4180 | -PRIVATE int strhash(x) | |
4181 | -char *x; | |
4794 | +PRIVATE unsigned strhash(const char *x) | |
4182 | 4795 | { |
4183 | - int h = 0; | |
4184 | - while( *x) h = h*13 + *(x++); | |
4796 | + unsigned h = 0; | |
4797 | + while( *x ) h = h*13 + *(x++); | |
4185 | 4798 | return h; |
4186 | 4799 | } |
4187 | 4800 |
@@ -4189,15 +4802,16 @@ | ||
4189 | 4802 | ** keep strings in a table so that the same string is not in more |
4190 | 4803 | ** than one place. |
4191 | 4804 | */ |
4192 | -char *Strsafe(y) | |
4193 | -char *y; | |
4805 | +const char *Strsafe(const char *y) | |
4194 | 4806 | { |
4195 | - char *z; | |
4807 | + const char *z; | |
4808 | + char *cpy; | |
4196 | 4809 | |
4197 | 4810 | if( y==0 ) return 0; |
4198 | 4811 | z = Strsafe_find(y); |
4199 | - if( z==0 && (z=malloc( strlen(y)+1 ))!=0 ){ | |
4200 | - strcpy(z,y); | |
4812 | + if( z==0 && (cpy=(char *)malloc( lemonStrlen(y)+1 ))!=0 ){ | |
4813 | + strcpy(cpy,y); | |
4814 | + z = cpy; | |
4201 | 4815 | Strsafe_insert(z); |
4202 | 4816 | } |
4203 | 4817 | MemoryCheck(z); |
@@ -4220,7 +4834,7 @@ | ||
4220 | 4834 | ** in an associative array of type "x1". |
4221 | 4835 | */ |
4222 | 4836 | typedef struct s_x1node { |
4223 | - char *data; /* The data */ | |
4837 | + const char *data; /* The data */ | |
4224 | 4838 | struct s_x1node *next; /* Next entry with the same hash */ |
4225 | 4839 | struct s_x1node **from; /* Previous link */ |
4226 | 4840 | } x1node; |
@@ -4235,8 +4849,7 @@ | ||
4235 | 4849 | if( x1a ){ |
4236 | 4850 | x1a->size = 1024; |
4237 | 4851 | x1a->count = 0; |
4238 | - x1a->tbl = (x1node*)malloc( | |
4239 | - (sizeof(x1node) + sizeof(x1node*))*1024 ); | |
4852 | + x1a->tbl = (x1node*)calloc(1024, sizeof(x1node) + sizeof(x1node*)); | |
4240 | 4853 | if( x1a->tbl==0 ){ |
4241 | 4854 | free(x1a); |
4242 | 4855 | x1a = 0; |
@@ -4249,12 +4862,11 @@ | ||
4249 | 4862 | } |
4250 | 4863 | /* Insert a new record into the array. Return TRUE if successful. |
4251 | 4864 | ** Prior data with the same key is NOT overwritten */ |
4252 | -int Strsafe_insert(data) | |
4253 | -char *data; | |
4865 | +int Strsafe_insert(const char *data) | |
4254 | 4866 | { |
4255 | 4867 | x1node *np; |
4256 | - int h; | |
4257 | - int ph; | |
4868 | + unsigned h; | |
4869 | + unsigned ph; | |
4258 | 4870 | |
4259 | 4871 | if( x1a==0 ) return 0; |
4260 | 4872 | ph = strhash(data); |
@@ -4274,8 +4886,7 @@ | ||
4274 | 4886 | struct s_x1 array; |
4275 | 4887 | array.size = size = x1a->size*2; |
4276 | 4888 | array.count = x1a->count; |
4277 | - array.tbl = (x1node*)malloc( | |
4278 | - (sizeof(x1node) + sizeof(x1node*))*size ); | |
4889 | + array.tbl = (x1node*)calloc(size, sizeof(x1node) + sizeof(x1node*)); | |
4279 | 4890 | if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ |
4280 | 4891 | array.ht = (x1node**)&(array.tbl[size]); |
4281 | 4892 | for(i=0; i<size; i++) array.ht[i] = 0; |
@@ -4306,10 +4917,9 @@ | ||
4306 | 4917 | |
4307 | 4918 | /* Return a pointer to data assigned to the given key. Return NULL |
4308 | 4919 | ** if no such key. */ |
4309 | -char *Strsafe_find(key) | |
4310 | -char *key; | |
4920 | +const char *Strsafe_find(const char *key) | |
4311 | 4921 | { |
4312 | - int h; | |
4922 | + unsigned h; | |
4313 | 4923 | x1node *np; |
4314 | 4924 | |
4315 | 4925 | if( x1a==0 ) return 0; |
@@ -4325,8 +4935,7 @@ | ||
4325 | 4935 | /* Return a pointer to the (terminal or nonterminal) symbol "x". |
4326 | 4936 | ** Create a new symbol if this is the first time "x" has been seen. |
4327 | 4937 | */ |
4328 | -struct symbol *Symbol_new(x) | |
4329 | -char *x; | |
4938 | +struct symbol *Symbol_new(const char *x) | |
4330 | 4939 | { |
4331 | 4940 | struct symbol *sp; |
4332 | 4941 |
@@ -4335,7 +4944,7 @@ | ||
4335 | 4944 | sp = (struct symbol *)calloc(1, sizeof(struct symbol) ); |
4336 | 4945 | MemoryCheck(sp); |
4337 | 4946 | sp->name = Strsafe(x); |
4338 | - sp->type = isupper(*x) ? TERMINAL : NONTERMINAL; | |
4947 | + sp->type = ISUPPER(*x) ? TERMINAL : NONTERMINAL; | |
4339 | 4948 | sp->rule = 0; |
4340 | 4949 | sp->fallback = 0; |
4341 | 4950 | sp->prec = -1; |
@@ -4343,6 +4952,7 @@ | ||
4343 | 4952 | sp->firstset = 0; |
4344 | 4953 | sp->lambda = LEMON_FALSE; |
4345 | 4954 | sp->destructor = 0; |
4955 | + sp->destLineno = 0; | |
4346 | 4956 | sp->datatype = 0; |
4347 | 4957 | sp->useCnt = 0; |
4348 | 4958 | Symbol_insert(sp,sp->name); |
@@ -4351,20 +4961,27 @@ | ||
4351 | 4961 | return sp; |
4352 | 4962 | } |
4353 | 4963 | |
4354 | -/* Compare two symbols for working purposes | |
4964 | +/* Compare two symbols for sorting purposes. Return negative, | |
4965 | +** zero, or positive if a is less then, equal to, or greater | |
4966 | +** than b. | |
4355 | 4967 | ** |
4356 | 4968 | ** Symbols that begin with upper case letters (terminals or tokens) |
4357 | 4969 | ** must sort before symbols that begin with lower case letters |
4358 | -** (non-terminals). Other than that, the order does not matter. | |
4970 | +** (non-terminals). And MULTITERMINAL symbols (created using the | |
4971 | +** %token_class directive) must sort at the very end. Other than | |
4972 | +** that, the order does not matter. | |
4359 | 4973 | ** |
4360 | 4974 | ** We find experimentally that leaving the symbols in their original |
4361 | 4975 | ** order (the order they appeared in the grammar file) gives the |
4362 | 4976 | ** smallest parser tables in SQLite. |
4363 | 4977 | */ |
4364 | -int Symbolcmpp(struct symbol **a, struct symbol **b){ | |
4365 | - int i1 = (**a).index + 10000000*((**a).name[0]>'Z'); | |
4366 | - int i2 = (**b).index + 10000000*((**b).name[0]>'Z'); | |
4367 | - return i1-i2; | |
4978 | +int Symbolcmpp(const void *_a, const void *_b) | |
4979 | +{ | |
4980 | + const struct symbol *a = *(const struct symbol **) _a; | |
4981 | + const struct symbol *b = *(const struct symbol **) _b; | |
4982 | + int i1 = a->type==MULTITERMINAL ? 3 : a->name[0]>'Z' ? 2 : 1; | |
4983 | + int i2 = b->type==MULTITERMINAL ? 3 : b->name[0]>'Z' ? 2 : 1; | |
4984 | + return i1==i2 ? a->index - b->index : i1 - i2; | |
4368 | 4985 | } |
4369 | 4986 | |
4370 | 4987 | /* There is one instance of the following structure for each |
@@ -4383,8 +5000,8 @@ | ||
4383 | 5000 | ** in an associative array of type "x2". |
4384 | 5001 | */ |
4385 | 5002 | typedef struct s_x2node { |
4386 | - struct symbol *data; /* The data */ | |
4387 | - char *key; /* The key */ | |
5003 | + struct symbol *data; /* The data */ | |
5004 | + const char *key; /* The key */ | |
4388 | 5005 | struct s_x2node *next; /* Next entry with the same hash */ |
4389 | 5006 | struct s_x2node **from; /* Previous link */ |
4390 | 5007 | } x2node; |
@@ -4399,8 +5016,7 @@ | ||
4399 | 5016 | if( x2a ){ |
4400 | 5017 | x2a->size = 128; |
4401 | 5018 | x2a->count = 0; |
4402 | - x2a->tbl = (x2node*)malloc( | |
4403 | - (sizeof(x2node) + sizeof(x2node*))*128 ); | |
5019 | + x2a->tbl = (x2node*)calloc(128, sizeof(x2node) + sizeof(x2node*)); | |
4404 | 5020 | if( x2a->tbl==0 ){ |
4405 | 5021 | free(x2a); |
4406 | 5022 | x2a = 0; |
@@ -4413,13 +5029,11 @@ | ||
4413 | 5029 | } |
4414 | 5030 | /* Insert a new record into the array. Return TRUE if successful. |
4415 | 5031 | ** Prior data with the same key is NOT overwritten */ |
4416 | -int Symbol_insert(data,key) | |
4417 | -struct symbol *data; | |
4418 | -char *key; | |
5032 | +int Symbol_insert(struct symbol *data, const char *key) | |
4419 | 5033 | { |
4420 | 5034 | x2node *np; |
4421 | - int h; | |
4422 | - int ph; | |
5035 | + unsigned h; | |
5036 | + unsigned ph; | |
4423 | 5037 | |
4424 | 5038 | if( x2a==0 ) return 0; |
4425 | 5039 | ph = strhash(key); |
@@ -4439,8 +5053,7 @@ | ||
4439 | 5053 | struct s_x2 array; |
4440 | 5054 | array.size = size = x2a->size*2; |
4441 | 5055 | array.count = x2a->count; |
4442 | - array.tbl = (x2node*)malloc( | |
4443 | - (sizeof(x2node) + sizeof(x2node*))*size ); | |
5056 | + array.tbl = (x2node*)calloc(size, sizeof(x2node) + sizeof(x2node*)); | |
4444 | 5057 | if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ |
4445 | 5058 | array.ht = (x2node**)&(array.tbl[size]); |
4446 | 5059 | for(i=0; i<size; i++) array.ht[i] = 0; |
@@ -4473,10 +5086,9 @@ | ||
4473 | 5086 | |
4474 | 5087 | /* Return a pointer to data assigned to the given key. Return NULL |
4475 | 5088 | ** if no such key. */ |
4476 | -struct symbol *Symbol_find(key) | |
4477 | -char *key; | |
5089 | +struct symbol *Symbol_find(const char *key) | |
4478 | 5090 | { |
4479 | - int h; | |
5091 | + unsigned h; | |
4480 | 5092 | x2node *np; |
4481 | 5093 | |
4482 | 5094 | if( x2a==0 ) return 0; |
@@ -4490,8 +5102,7 @@ | ||
4490 | 5102 | } |
4491 | 5103 | |
4492 | 5104 | /* Return the n-th data. Return NULL if n is out of range. */ |
4493 | -struct symbol *Symbol_Nth(n) | |
4494 | -int n; | |
5105 | +struct symbol *Symbol_Nth(int n) | |
4495 | 5106 | { |
4496 | 5107 | struct symbol *data; |
4497 | 5108 | if( x2a && n>0 && n<=x2a->count ){ |
@@ -4525,10 +5136,10 @@ | ||
4525 | 5136 | } |
4526 | 5137 | |
4527 | 5138 | /* Compare two configurations */ |
4528 | -int Configcmp(a,b) | |
4529 | -struct config *a; | |
4530 | -struct config *b; | |
5139 | +int Configcmp(const char *_a,const char *_b) | |
4531 | 5140 | { |
5141 | + const struct config *a = (struct config *) _a; | |
5142 | + const struct config *b = (struct config *) _b; | |
4532 | 5143 | int x; |
4533 | 5144 | x = a->rp->index - b->rp->index; |
4534 | 5145 | if( x==0 ) x = a->dot - b->dot; |
@@ -4536,9 +5147,7 @@ | ||
4536 | 5147 | } |
4537 | 5148 | |
4538 | 5149 | /* Compare two states */ |
4539 | -PRIVATE int statecmp(a,b) | |
4540 | -struct config *a; | |
4541 | -struct config *b; | |
5150 | +PRIVATE int statecmp(struct config *a, struct config *b) | |
4542 | 5151 | { |
4543 | 5152 | int rc; |
4544 | 5153 | for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){ |
@@ -4553,10 +5162,9 @@ | ||
4553 | 5162 | } |
4554 | 5163 | |
4555 | 5164 | /* Hash a state */ |
4556 | -PRIVATE int statehash(a) | |
4557 | -struct config *a; | |
5165 | +PRIVATE unsigned statehash(struct config *a) | |
4558 | 5166 | { |
4559 | - int h=0; | |
5167 | + unsigned h=0; | |
4560 | 5168 | while( a ){ |
4561 | 5169 | h = h*571 + a->rp->index*37 + a->dot; |
4562 | 5170 | a = a->bp; |
@@ -4567,10 +5175,10 @@ | ||
4567 | 5175 | /* Allocate a new state structure */ |
4568 | 5176 | struct state *State_new() |
4569 | 5177 | { |
4570 | - struct state *new; | |
4571 | - new = (struct state *)calloc(1, sizeof(struct state) ); | |
4572 | - MemoryCheck(new); | |
4573 | - return new; | |
5178 | + struct state *newstate; | |
5179 | + newstate = (struct state *)calloc(1, sizeof(struct state) ); | |
5180 | + MemoryCheck(newstate); | |
5181 | + return newstate; | |
4574 | 5182 | } |
4575 | 5183 | |
4576 | 5184 | /* There is one instance of the following structure for each |
@@ -4605,8 +5213,7 @@ | ||
4605 | 5213 | if( x3a ){ |
4606 | 5214 | x3a->size = 128; |
4607 | 5215 | x3a->count = 0; |
4608 | - x3a->tbl = (x3node*)malloc( | |
4609 | - (sizeof(x3node) + sizeof(x3node*))*128 ); | |
5216 | + x3a->tbl = (x3node*)calloc(128, sizeof(x3node) + sizeof(x3node*)); | |
4610 | 5217 | if( x3a->tbl==0 ){ |
4611 | 5218 | free(x3a); |
4612 | 5219 | x3a = 0; |
@@ -4619,13 +5226,11 @@ | ||
4619 | 5226 | } |
4620 | 5227 | /* Insert a new record into the array. Return TRUE if successful. |
4621 | 5228 | ** Prior data with the same key is NOT overwritten */ |
4622 | -int State_insert(data,key) | |
4623 | -struct state *data; | |
4624 | -struct config *key; | |
5229 | +int State_insert(struct state *data, struct config *key) | |
4625 | 5230 | { |
4626 | 5231 | x3node *np; |
4627 | - int h; | |
4628 | - int ph; | |
5232 | + unsigned h; | |
5233 | + unsigned ph; | |
4629 | 5234 | |
4630 | 5235 | if( x3a==0 ) return 0; |
4631 | 5236 | ph = statehash(key); |
@@ -4645,8 +5250,7 @@ | ||
4645 | 5250 | struct s_x3 array; |
4646 | 5251 | array.size = size = x3a->size*2; |
4647 | 5252 | array.count = x3a->count; |
4648 | - array.tbl = (x3node*)malloc( | |
4649 | - (sizeof(x3node) + sizeof(x3node*))*size ); | |
5253 | + array.tbl = (x3node*)calloc(size, sizeof(x3node) + sizeof(x3node*)); | |
4650 | 5254 | if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ |
4651 | 5255 | array.ht = (x3node**)&(array.tbl[size]); |
4652 | 5256 | for(i=0; i<size; i++) array.ht[i] = 0; |
@@ -4679,10 +5283,9 @@ | ||
4679 | 5283 | |
4680 | 5284 | /* Return a pointer to data assigned to the given key. Return NULL |
4681 | 5285 | ** if no such key. */ |
4682 | -struct state *State_find(key) | |
4683 | -struct config *key; | |
5286 | +struct state *State_find(struct config *key) | |
4684 | 5287 | { |
4685 | - int h; | |
5288 | + unsigned h; | |
4686 | 5289 | x3node *np; |
4687 | 5290 | |
4688 | 5291 | if( x3a==0 ) return 0; |
@@ -4704,7 +5307,7 @@ | ||
4704 | 5307 | int i,size; |
4705 | 5308 | if( x3a==0 ) return 0; |
4706 | 5309 | size = x3a->count; |
4707 | - array = (struct state **)malloc( sizeof(struct state *)*size ); | |
5310 | + array = (struct state **)calloc(size, sizeof(struct state *)); | |
4708 | 5311 | if( array ){ |
4709 | 5312 | for(i=0; i<size; i++) array[i] = x3a->tbl[i].data; |
4710 | 5313 | } |
@@ -4712,10 +5315,9 @@ | ||
4712 | 5315 | } |
4713 | 5316 | |
4714 | 5317 | /* Hash a configuration */ |
4715 | -PRIVATE int confighash(a) | |
4716 | -struct config *a; | |
5318 | +PRIVATE unsigned confighash(struct config *a) | |
4717 | 5319 | { |
4718 | - int h=0; | |
5320 | + unsigned h=0; | |
4719 | 5321 | h = h*571 + a->rp->index*37 + a->dot; |
4720 | 5322 | return h; |
4721 | 5323 | } |
@@ -4751,8 +5353,7 @@ | ||
4751 | 5353 | if( x4a ){ |
4752 | 5354 | x4a->size = 64; |
4753 | 5355 | x4a->count = 0; |
4754 | - x4a->tbl = (x4node*)malloc( | |
4755 | - (sizeof(x4node) + sizeof(x4node*))*64 ); | |
5356 | + x4a->tbl = (x4node*)calloc(64, sizeof(x4node) + sizeof(x4node*)); | |
4756 | 5357 | if( x4a->tbl==0 ){ |
4757 | 5358 | free(x4a); |
4758 | 5359 | x4a = 0; |
@@ -4765,19 +5366,18 @@ | ||
4765 | 5366 | } |
4766 | 5367 | /* Insert a new record into the array. Return TRUE if successful. |
4767 | 5368 | ** Prior data with the same key is NOT overwritten */ |
4768 | -int Configtable_insert(data) | |
4769 | -struct config *data; | |
5369 | +int Configtable_insert(struct config *data) | |
4770 | 5370 | { |
4771 | 5371 | x4node *np; |
4772 | - int h; | |
4773 | - int ph; | |
5372 | + unsigned h; | |
5373 | + unsigned ph; | |
4774 | 5374 | |
4775 | 5375 | if( x4a==0 ) return 0; |
4776 | 5376 | ph = confighash(data); |
4777 | 5377 | h = ph & (x4a->size-1); |
4778 | 5378 | np = x4a->ht[h]; |
4779 | 5379 | while( np ){ |
4780 | - if( Configcmp(np->data,data)==0 ){ | |
5380 | + if( Configcmp((const char *) np->data,(const char *) data)==0 ){ | |
4781 | 5381 | /* An existing entry with the same key is found. */ |
4782 | 5382 | /* Fail because overwrite is not allows. */ |
4783 | 5383 | return 0; |
@@ -4790,8 +5390,7 @@ | ||
4790 | 5390 | struct s_x4 array; |
4791 | 5391 | array.size = size = x4a->size*2; |
4792 | 5392 | array.count = x4a->count; |
4793 | - array.tbl = (x4node*)malloc( | |
4794 | - (sizeof(x4node) + sizeof(x4node*))*size ); | |
5393 | + array.tbl = (x4node*)calloc(size, sizeof(x4node) + sizeof(x4node*)); | |
4795 | 5394 | if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ |
4796 | 5395 | array.ht = (x4node**)&(array.tbl[size]); |
4797 | 5396 | for(i=0; i<size; i++) array.ht[i] = 0; |
@@ -4822,8 +5421,7 @@ | ||
4822 | 5421 | |
4823 | 5422 | /* Return a pointer to data assigned to the given key. Return NULL |
4824 | 5423 | ** if no such key. */ |
4825 | -struct config *Configtable_find(key) | |
4826 | -struct config *key; | |
5424 | +struct config *Configtable_find(struct config *key) | |
4827 | 5425 | { |
4828 | 5426 | int h; |
4829 | 5427 | x4node *np; |
@@ -4832,7 +5430,7 @@ | ||
4832 | 5430 | h = confighash(key) & (x4a->size-1); |
4833 | 5431 | np = x4a->ht[h]; |
4834 | 5432 | while( np ){ |
4835 | - if( Configcmp(np->data,key)==0 ) break; | |
5433 | + if( Configcmp((const char *) np->data,(const char *) key)==0 ) break; | |
4836 | 5434 | np = np->next; |
4837 | 5435 | } |
4838 | 5436 | return np ? np->data : 0; |
@@ -4840,8 +5438,7 @@ | ||
4840 | 5438 | |
4841 | 5439 | /* Remove all data from the table. Pass each data to the function "f" |
4842 | 5440 | ** as it is removed. ("f" may be null to avoid this step.) */ |
4843 | -void Configtable_clear(f) | |
4844 | -int(*f)(/* struct config * */); | |
5441 | +void Configtable_clear(int(*f)(struct config *)) | |
4845 | 5442 | { |
4846 | 5443 | int i; |
4847 | 5444 | if( x4a==0 || x4a->count==0 ) return; |
@@ -1,8 +1,27 @@ | ||
1 | -/* Driver template for the LEMON parser generator. | |
2 | -** The author disclaims copyright to this source code. | |
1 | +/* | |
2 | +** 2000-05-29 | |
3 | +** | |
4 | +** The author disclaims copyright to this source code. In place of | |
5 | +** a legal notice, here is a blessing: | |
6 | +** | |
7 | +** May you do good and not evil. | |
8 | +** May you find forgiveness for yourself and forgive others. | |
9 | +** May you share freely, never taking more than you give. | |
10 | +** | |
11 | +************************************************************************* | |
12 | +** Driver template for the LEMON parser generator. | |
13 | +** | |
14 | +** The "lemon" program processes an LALR(1) input grammar file, then uses | |
15 | +** this template to construct a parser. The "lemon" program inserts text | |
16 | +** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the | |
17 | +** interstitial "-" characters) contained in this template is changed into | |
18 | +** the value of the %name directive from the grammar. Otherwise, the content | |
19 | +** of this template is copied straight through into the generate parser | |
20 | +** source file. | |
21 | +** | |
22 | +** The following is the concatenation of all %include directives from the | |
23 | +** input grammar file: | |
3 | 24 | */ |
4 | -/* First off, code is included which follows the "include" declaration | |
5 | -** in the input file. */ | |
6 | 25 | #include <stdio.h> |
7 | 26 | #include <string.h> |
8 | 27 | #include <assert.h> |
@@ -13,63 +32,84 @@ | ||
13 | 32 | #define CDECL |
14 | 33 | #endif |
15 | 34 | |
16 | -%% | |
17 | -/* Next is all token values, in a form suitable for use by makeheaders. | |
18 | -** This section will be null unless lemon is run with the -m switch. | |
19 | -*/ | |
20 | -/* | |
21 | -** These constants (all generated automatically by the parser generator) | |
22 | -** specify the various kinds of tokens (terminals) that the parser | |
23 | -** understands. | |
24 | -** | |
25 | -** Each symbol here is a terminal symbol in the grammar. | |
26 | -*/ | |
35 | +/************ Begin %include sections from the grammar ************************/ | |
27 | 36 | %% |
28 | -/* Make sure the INTERFACE macro is defined. | |
29 | -*/ | |
30 | -#ifndef INTERFACE | |
31 | -# define INTERFACE 1 | |
32 | -#endif | |
33 | -/* The next thing included is series of defines which control | |
37 | +/**************** End of %include directives **********************************/ | |
38 | +/* These constants specify the various numeric values for terminal symbols | |
39 | +** in a format understandable to "makeheaders". This section is blank unless | |
40 | +** "lemon" is run with the "-m" command-line option. | |
41 | +***************** Begin makeheaders token definitions *************************/ | |
42 | +%% | |
43 | +/**************** End makeheaders token definitions ***************************/ | |
44 | + | |
45 | +/* The next section is a series of control #defines. | |
34 | 46 | ** various aspects of the generated parser. |
35 | -** YYCODETYPE is the data type used for storing terminal | |
36 | -** and nonterminal numbers. "unsigned char" is | |
37 | -** used if there are fewer than 250 terminals | |
38 | -** and nonterminals. "int" is used otherwise. | |
39 | -** YYNOCODE is a number of type YYCODETYPE which corresponds | |
40 | -** to no legal terminal or nonterminal number. This | |
41 | -** number is used to fill in empty slots of the hash | |
42 | -** table. | |
47 | +** YYCODETYPE is the data type used to store the integer codes | |
48 | +** that represent terminal and non-terminal symbols. | |
49 | +** "unsigned char" is used if there are fewer than | |
50 | +** 256 symbols. Larger types otherwise. | |
51 | +** YYNOCODE is a number of type YYCODETYPE that is not used for | |
52 | +** any terminal or nonterminal symbol. | |
43 | 53 | ** YYFALLBACK If defined, this indicates that one or more tokens |
44 | -** have fall-back values which should be used if the | |
45 | -** original value of the token will not parse. | |
46 | -** YYACTIONTYPE is the data type used for storing terminal | |
47 | -** and nonterminal numbers. "unsigned char" is | |
48 | -** used if there are fewer than 250 rules and | |
49 | -** states combined. "int" is used otherwise. | |
50 | -** ParseTOKENTYPE is the data type used for minor tokens given | |
51 | -** directly to the parser from the tokenizer. | |
52 | -** YYMINORTYPE is the data type used for all minor tokens. | |
54 | +** (also known as: "terminal symbols") have fall-back | |
55 | +** values which should be used if the original symbol | |
56 | +** would not parse. This permits keywords to sometimes | |
57 | +** be used as identifiers, for example. | |
58 | +** YYACTIONTYPE is the data type used for "action codes" - numbers | |
59 | +** that indicate what to do in response to the next | |
60 | +** token. | |
61 | +** ParseTOKENTYPE is the data type used for minor type for terminal | |
62 | +** symbols. Background: A "minor type" is a semantic | |
63 | +** value associated with a terminal or non-terminal | |
64 | +** symbols. For example, for an "ID" terminal symbol, | |
65 | +** the minor type might be the name of the identifier. | |
66 | +** Each non-terminal can have a different minor type. | |
67 | +** Terminal symbols all have the same minor type, though. | |
68 | +** This macros defines the minor type for terminal | |
69 | +** symbols. | |
70 | +** YYMINORTYPE is the data type used for all minor types. | |
53 | 71 | ** This is typically a union of many types, one of |
54 | 72 | ** which is ParseTOKENTYPE. The entry in the union |
55 | -** for base tokens is called "yy0". | |
73 | +** for terminal symbols is called "yy0". | |
56 | 74 | ** YYSTACKDEPTH is the maximum depth of the parser's stack. If |
57 | 75 | ** zero the stack is dynamically sized using realloc() |
58 | 76 | ** ParseARG_SDECL A static variable declaration for the %extra_argument |
59 | 77 | ** ParseARG_PDECL A parameter declaration for the %extra_argument |
60 | 78 | ** ParseARG_STORE Code to store %extra_argument into yypParser |
61 | 79 | ** ParseARG_FETCH Code to extract %extra_argument from yypParser |
62 | -** YYNSTATE the combined number of states. | |
63 | -** YYNRULE the number of rules in the grammar | |
64 | 80 | ** YYERRORSYMBOL is the code number of the error symbol. If not |
65 | 81 | ** defined, then do no error processing. |
82 | +** YYNSTATE the combined number of states. | |
83 | +** YYNRULE the number of rules in the grammar | |
84 | +** YY_MAX_SHIFT Maximum value for shift actions | |
85 | +** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions | |
86 | +** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions | |
87 | +** YY_MIN_REDUCE Maximum value for reduce actions | |
88 | +** YY_ERROR_ACTION The yy_action[] code for syntax error | |
89 | +** YY_ACCEPT_ACTION The yy_action[] code for accept | |
90 | +** YY_NO_ACTION The yy_action[] code for no-op | |
66 | 91 | */ |
92 | +#ifndef INTERFACE | |
93 | +# define INTERFACE 1 | |
94 | +#endif | |
95 | +/************* Begin control #defines *****************************************/ | |
67 | 96 | %% |
68 | -#define YY_NO_ACTION (YYNSTATE+YYNRULE+2) | |
69 | -#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) | |
70 | -#define YY_ERROR_ACTION (YYNSTATE+YYNRULE) | |
97 | +/************* End control #defines *******************************************/ | |
71 | 98 | |
72 | -/* Next are that tables used to determine what action to take based on the | |
99 | +/* Define the yytestcase() macro to be a no-op if is not already defined | |
100 | +** otherwise. | |
101 | +** | |
102 | +** Applications can choose to define yytestcase() in the %include section | |
103 | +** to a macro that can assist in verifying code coverage. For production | |
104 | +** code the yytestcase() macro should be turned off. But it is useful | |
105 | +** for testing. | |
106 | +*/ | |
107 | +#ifndef yytestcase | |
108 | +# define yytestcase(X) | |
109 | +#endif | |
110 | + | |
111 | + | |
112 | +/* Next are the tables used to determine what action to take based on the | |
73 | 113 | ** current state and lookahead token. These tables are used to implement |
74 | 114 | ** functions that take a state number and lookahead value and return an |
75 | 115 | ** action integer. |
@@ -77,29 +117,37 @@ | ||
77 | 117 | ** Suppose the action integer is N. Then the action is determined as |
78 | 118 | ** follows |
79 | 119 | ** |
80 | -** 0 <= N < YYNSTATE Shift N. That is, push the lookahead | |
120 | +** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead | |
81 | 121 | ** token onto the stack and goto state N. |
82 | 122 | ** |
83 | -** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. | |
123 | +** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then | |
124 | +** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. | |
84 | 125 | ** |
85 | -** N == YYNSTATE+YYNRULE A syntax error has occurred. | |
126 | +** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE | |
127 | +** and YY_MAX_REDUCE | |
86 | 128 | ** |
87 | -** N == YYNSTATE+YYNRULE+1 The parser accepts its input. | |
129 | +** N == YY_ERROR_ACTION A syntax error has occurred. | |
88 | 130 | ** |
89 | -** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused | |
131 | +** N == YY_ACCEPT_ACTION The parser accepts its input. | |
132 | +** | |
133 | +** N == YY_NO_ACTION No such action. Denotes unused | |
90 | 134 | ** slots in the yy_action[] table. |
91 | 135 | ** |
92 | 136 | ** The action table is constructed as a single large table named yy_action[]. |
93 | -** Given state S and lookahead X, the action is computed as | |
94 | -** | |
95 | -** yy_action[ yy_shift_ofst[S] + X ] | |
137 | +** Given state S and lookahead X, the action is computed as either: | |
96 | 138 | ** |
97 | -** If the index value yy_shift_ofst[S]+X is out of range or if the value | |
98 | -** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] | |
99 | -** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table | |
100 | -** and that yy_default[S] should be used instead. | |
139 | +** (A) N = yy_action[ yy_shift_ofst[S] + X ] | |
140 | +** (B) N = yy_default[S] | |
101 | 141 | ** |
102 | -** The formula above is for computing the action when the lookahead is | |
142 | +** The (A) formula is preferred. The B formula is used instead if: | |
143 | +** (1) The yy_shift_ofst[S]+X value is out of range, or | |
144 | +** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or | |
145 | +** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT. | |
146 | +** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that | |
147 | +** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. | |
148 | +** Hence only tests (1) and (2) need to be evaluated.) | |
149 | +** | |
150 | +** The formulas above are for computing the action when the lookahead is | |
103 | 151 | ** a terminal symbol. If the lookahead is a non-terminal (as occurs after |
104 | 152 | ** a reduce action) then the yy_reduce_ofst[] array is used in place of |
105 | 153 | ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of |
@@ -115,19 +163,24 @@ | ||
115 | 163 | ** yy_reduce_ofst[] For each state, the offset into yy_action for |
116 | 164 | ** shifting non-terminals after a reduce. |
117 | 165 | ** yy_default[] Default action for each state. |
118 | -*/ | |
166 | +** | |
167 | +*********** Begin parsing tables **********************************************/ | |
119 | 168 | %% |
120 | -#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0])) | |
169 | +/********** End of lemon-generated parsing tables *****************************/ | |
121 | 170 | |
122 | -/* The next table maps tokens into fallback tokens. If a construct | |
123 | -** like the following: | |
171 | +/* The next table maps tokens (terminal symbols) into fallback tokens. | |
172 | +** If a construct like the following: | |
124 | 173 | ** |
125 | 174 | ** %fallback ID X Y Z. |
126 | 175 | ** |
127 | -** appears in the grammer, then ID becomes a fallback token for X, Y, | |
176 | +** appears in the grammar, then ID becomes a fallback token for X, Y, | |
128 | 177 | ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser |
129 | 178 | ** but it does not parse, the type of the token is changed to ID and |
130 | 179 | ** the parse is retried before an error is thrown. |
180 | +** | |
181 | +** This feature can be used, for example, to cause some keywords in a language | |
182 | +** to revert to identifiers if they keyword does not apply in the context where | |
183 | +** it appears. | |
131 | 184 | */ |
132 | 185 | #ifdef YYFALLBACK |
133 | 186 | static const YYCODETYPE yyFallback[] = { |
@@ -146,25 +199,35 @@ | ||
146 | 199 | ** + The semantic value stored at this level of the stack. This is |
147 | 200 | ** the information used by the action routines in the grammar. |
148 | 201 | ** It is sometimes called the "minor" token. |
202 | +** | |
203 | +** After the "shift" half of a SHIFTREDUCE action, the stateno field | |
204 | +** actually contains the reduce action for the second half of the | |
205 | +** SHIFTREDUCE. | |
149 | 206 | */ |
150 | 207 | struct yyStackEntry { |
151 | - int stateno; /* The state-number */ | |
152 | - int major; /* The major token value. This is the code | |
153 | - ** number for the token at this stack level */ | |
154 | - YYMINORTYPE minor; /* The user-supplied minor token value. This | |
155 | - ** is the value of the token */ | |
208 | + YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ | |
209 | + YYCODETYPE major; /* The major token value. This is the code | |
210 | + ** number for the token at this stack level */ | |
211 | + YYMINORTYPE minor; /* The user-supplied minor token value. This | |
212 | + ** is the value of the token */ | |
156 | 213 | }; |
157 | 214 | typedef struct yyStackEntry yyStackEntry; |
158 | 215 | |
159 | 216 | /* The state of the parser is completely contained in an instance of |
160 | 217 | ** the following structure */ |
161 | 218 | struct yyParser { |
162 | - int yyidx; /* Index of top element in stack */ | |
219 | + yyStackEntry *yytos; /* Pointer to top element of the stack */ | |
220 | +#ifdef YYTRACKMAXSTACKDEPTH | |
221 | + int yyhwm; /* High-water mark of the stack */ | |
222 | +#endif | |
223 | +#ifndef YYNOERRORRECOVERY | |
163 | 224 | int yyerrcnt; /* Shifts left before out of the error */ |
225 | +#endif | |
164 | 226 | ParseARG_SDECL /* A place to hold %extra_argument */ |
165 | 227 | #if YYSTACKDEPTH<=0 |
166 | 228 | int yystksz; /* Current side of the stack */ |
167 | 229 | yyStackEntry *yystack; /* The parser's stack */ |
230 | + yyStackEntry yystk0; /* First stack entry */ | |
168 | 231 | #else |
169 | 232 | yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ |
170 | 233 | #endif |
@@ -219,29 +282,50 @@ | ||
219 | 282 | }; |
220 | 283 | #endif /* NDEBUG */ |
221 | 284 | |
285 | + | |
222 | 286 | #if YYSTACKDEPTH<=0 |
223 | 287 | /* |
224 | -** Try to increase the size of the parser stack. | |
288 | +** Try to increase the size of the parser stack. Return the number | |
289 | +** of errors. Return 0 on success. | |
225 | 290 | */ |
226 | -static void yyGrowStack(yyParser *p){ | |
291 | +static int yyGrowStack(yyParser *p){ | |
227 | 292 | int newSize; |
293 | + int idx; | |
228 | 294 | yyStackEntry *pNew; |
229 | 295 | |
230 | 296 | newSize = p->yystksz*2 + 100; |
231 | - pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); | |
297 | + idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; | |
298 | + if( p->yystack==&p->yystk0 ){ | |
299 | + pNew = (yyStackEntry *)malloc(newSize*sizeof(pNew[0])); | |
300 | + if( pNew ) pNew[0] = p->yystk0; | |
301 | + }else{ | |
302 | + pNew = (yyStackEntry *)realloc(p->yystack, newSize*sizeof(pNew[0])); | |
303 | + } | |
232 | 304 | if( pNew ){ |
233 | 305 | p->yystack = pNew; |
234 | - p->yystksz = newSize; | |
306 | + p->yytos = &p->yystack[idx]; | |
235 | 307 | #ifndef NDEBUG |
236 | 308 | if( yyTraceFILE ){ |
237 | - fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", | |
238 | - yyTracePrompt, p->yystksz); | |
309 | + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", | |
310 | + yyTracePrompt, p->yystksz, newSize); | |
311 | + fflush(yyTraceFILE); | |
239 | 312 | } |
240 | 313 | #endif |
314 | + p->yystksz = newSize; | |
241 | 315 | } |
316 | + return pNew==0; | |
242 | 317 | } |
243 | 318 | #endif |
244 | 319 | |
320 | +/* Datatype of the argument to the memory allocated passed as the | |
321 | +** second argument to ParseAlloc() below. This can be changed by | |
322 | +** putting an appropriate #define in the %include section of the input | |
323 | +** grammar. | |
324 | +*/ | |
325 | +#ifndef YYMALLOCARGTYPE | |
326 | +# define YYMALLOCARGTYPE size_t | |
327 | +#endif | |
328 | + | |
245 | 329 | /* |
246 | 330 | ** This function allocates a new parser. |
247 | 331 | ** The only argument is a pointer to a function which works like |
@@ -254,24 +338,45 @@ | ||
254 | 338 | ** A pointer to a parser. This pointer is used in subsequent calls |
255 | 339 | ** to Parse and ParseFree. |
256 | 340 | */ |
257 | -void *ParseAlloc(void *(CDECL *mallocProc)(size_t)){ | |
341 | +void *ParseAlloc(void *(CDECL *mallocProc)(YYMALLOCARGTYPE)){ | |
258 | 342 | yyParser *pParser; |
259 | - pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); | |
343 | + pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); | |
260 | 344 | if( pParser ){ |
261 | - pParser->yyidx = -1; | |
345 | +#ifdef YYTRACKMAXSTACKDEPTH | |
346 | + pParser->yyhwm = 0; | |
347 | +#endif | |
262 | 348 | #if YYSTACKDEPTH<=0 |
263 | - yyGrowStack(pParser); | |
349 | + pParser->yytos = NULL; | |
350 | + pParser->yystack = NULL; | |
351 | + pParser->yystksz = 0; | |
352 | + if( yyGrowStack(pParser) ){ | |
353 | + pParser->yystack = &pParser->yystk0; | |
354 | + pParser->yystksz = 1; | |
355 | + } | |
264 | 356 | #endif |
357 | +#ifndef YYNOERRORRECOVERY | |
358 | + pParser->yyerrcnt = -1; | |
359 | +#endif | |
360 | + pParser->yytos = pParser->yystack; | |
361 | + pParser->yystack[0].stateno = 0; | |
362 | + pParser->yystack[0].major = 0; | |
265 | 363 | } |
266 | 364 | return pParser; |
267 | 365 | } |
268 | 366 | |
269 | -/* The following function deletes the value associated with a | |
270 | -** symbol. The symbol can be either a terminal or nonterminal. | |
271 | -** "yymajor" is the symbol code, and "yypminor" is a pointer to | |
272 | -** the value. | |
367 | +/* The following function deletes the "minor type" or semantic value | |
368 | +** associated with a symbol. The symbol can be either a terminal | |
369 | +** or nonterminal. "yymajor" is the symbol code, and "yypminor" is | |
370 | +** a pointer to the value to be deleted. The code used to do the | |
371 | +** deletions is derived from the %destructor and/or %token_destructor | |
372 | +** directives of the input grammar. | |
273 | 373 | */ |
274 | -static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ | |
374 | +static void yy_destructor( | |
375 | + yyParser *yypParser, /* The parser */ | |
376 | + YYCODETYPE yymajor, /* Type code for object to destroy */ | |
377 | + YYMINORTYPE *yypminor /* The object to be destroyed */ | |
378 | +){ | |
379 | + ParseARG_FETCH; | |
275 | 380 | switch( yymajor ){ |
276 | 381 | /* Here is inserted the actions which take place when a |
277 | 382 | ** terminal or non-terminal is destroyed. This can happen |
@@ -280,10 +385,12 @@ | ||
280 | 385 | ** being destroyed before it is finished parsing. |
281 | 386 | ** |
282 | 387 | ** Note: during a reduce, the only symbols destroyed are those |
283 | - ** which appear on the RHS of the rule, but which are not used | |
388 | + ** which appear on the RHS of the rule, but which are *not* used | |
284 | 389 | ** inside the C code. |
285 | 390 | */ |
391 | +/********* Begin destructor definitions ***************************************/ | |
286 | 392 | %% |
393 | +/********* End destructor definitions *****************************************/ | |
287 | 394 | default: break; /* If no destructor action specified: do nothing */ |
288 | 395 | } |
289 | 396 | } |
@@ -293,193 +400,232 @@ | ||
293 | 400 | ** |
294 | 401 | ** If there is a destructor routine associated with the token which |
295 | 402 | ** is popped from the stack, then call it. |
296 | -** | |
297 | -** Return the major token number for the symbol popped. | |
298 | 403 | */ |
299 | -static int yy_pop_parser_stack(yyParser *pParser){ | |
300 | - YYCODETYPE yymajor; | |
301 | - yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; | |
302 | - | |
303 | - if( pParser->yyidx<0 ) return 0; | |
404 | +static void yy_pop_parser_stack(yyParser *pParser){ | |
405 | + yyStackEntry *yytos; | |
406 | + assert( pParser->yytos!=0 ); | |
407 | + assert( pParser->yytos > pParser->yystack ); | |
408 | + yytos = pParser->yytos--; | |
304 | 409 | #ifndef NDEBUG |
305 | - if( yyTraceFILE && pParser->yyidx>=0 ){ | |
410 | + if( yyTraceFILE ){ | |
306 | 411 | fprintf(yyTraceFILE,"%sPopping %s\n", |
307 | 412 | yyTracePrompt, |
308 | 413 | yyTokenName[yytos->major]); |
414 | + fflush(yyTraceFILE); | |
309 | 415 | } |
310 | 416 | #endif |
311 | - yymajor = yytos->major; | |
312 | - yy_destructor( yymajor, &yytos->minor); | |
313 | - pParser->yyidx--; | |
314 | - return yymajor; | |
417 | + yy_destructor(pParser, yytos->major, &yytos->minor); | |
315 | 418 | } |
316 | 419 | |
317 | 420 | /* |
318 | -** Deallocate and destroy a parser. Destructors are all called for | |
421 | +** Deallocate and destroy a parser. Destructors are called for | |
319 | 422 | ** all stack elements before shutting the parser down. |
320 | 423 | ** |
321 | -** Inputs: | |
322 | -** <ul> | |
323 | -** <li> A pointer to the parser. This should be a pointer | |
324 | -** obtained from ParseAlloc. | |
325 | -** <li> A pointer to a function used to reclaim memory obtained | |
326 | -** from malloc. | |
327 | -** </ul> | |
424 | +** If the YYPARSEFREENEVERNULL macro exists (for example because it | |
425 | +** is defined in a %include section of the input grammar) then it is | |
426 | +** assumed that the input pointer is never NULL. | |
328 | 427 | */ |
329 | 428 | void ParseFree( |
330 | 429 | void *p, /* The parser to be deleted */ |
331 | 430 | void (CDECL *freeProc)(void*) /* Function used to reclaim memory */ |
332 | 431 | ){ |
333 | 432 | yyParser *pParser = (yyParser*)p; |
433 | +#ifndef YYPARSEFREENEVERNULL | |
334 | 434 | if( pParser==0 ) return; |
335 | - while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); | |
435 | +#endif | |
436 | + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); | |
336 | 437 | #if YYSTACKDEPTH<=0 |
337 | - free(pParser->yystack); | |
438 | + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); | |
338 | 439 | #endif |
339 | 440 | (*freeProc)((void*)pParser); |
340 | 441 | } |
341 | 442 | |
342 | 443 | /* |
444 | +** Return the peak depth of the stack for a parser. | |
445 | +*/ | |
446 | +#ifdef YYTRACKMAXSTACKDEPTH | |
447 | +int ParseStackPeak(void *p){ | |
448 | + yyParser *pParser = (yyParser*)p; | |
449 | + return pParser->yyhwm; | |
450 | +} | |
451 | +#endif | |
452 | + | |
453 | +/* | |
343 | 454 | ** Find the appropriate action for a parser given the terminal |
344 | 455 | ** look-ahead token iLookAhead. |
345 | -** | |
346 | -** If the look-ahead token is YYNOCODE, then check to see if the action is | |
347 | -** independent of the look-ahead. If it is, return the action, otherwise | |
348 | -** return YY_NO_ACTION. | |
349 | 456 | */ |
350 | -static int yy_find_shift_action( | |
457 | +static unsigned int yy_find_shift_action( | |
351 | 458 | yyParser *pParser, /* The parser */ |
352 | 459 | YYCODETYPE iLookAhead /* The look-ahead token */ |
353 | 460 | ){ |
354 | 461 | int i; |
355 | - int stateno = pParser->yystack[pParser->yyidx].stateno; | |
462 | + int stateno = pParser->yytos->stateno; | |
356 | 463 | |
357 | - if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ | |
358 | - return yy_default[stateno]; | |
359 | - } | |
360 | - assert( iLookAhead!=YYNOCODE ); | |
361 | - i += iLookAhead; | |
362 | - if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ | |
363 | - if( iLookAhead>0 ){ | |
464 | + if( stateno>=YY_MIN_REDUCE ) return stateno; | |
465 | + assert( stateno <= YY_SHIFT_COUNT ); | |
466 | + do{ | |
467 | + i = yy_shift_ofst[stateno]; | |
468 | + assert( iLookAhead!=YYNOCODE ); | |
469 | + i += iLookAhead; | |
470 | + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ | |
364 | 471 | #ifdef YYFALLBACK |
365 | - int iFallback; /* Fallback token */ | |
472 | + YYCODETYPE iFallback; /* Fallback token */ | |
366 | 473 | if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) |
367 | 474 | && (iFallback = yyFallback[iLookAhead])!=0 ){ |
368 | 475 | #ifndef NDEBUG |
369 | 476 | if( yyTraceFILE ){ |
370 | 477 | fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", |
371 | 478 | yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); |
479 | + fflush(yyTraceFILE); | |
372 | 480 | } |
373 | 481 | #endif |
374 | - return yy_find_shift_action(pParser, iFallback); | |
482 | + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ | |
483 | + iLookAhead = iFallback; | |
484 | + continue; | |
375 | 485 | } |
376 | 486 | #endif |
377 | 487 | #ifdef YYWILDCARD |
378 | 488 | { |
379 | 489 | int j = i - iLookAhead + YYWILDCARD; |
380 | - if( j>=0 && j<YY_SZ_ACTTAB && yy_lookahead[j]==YYWILDCARD ){ | |
490 | + if( | |
491 | +#if YY_SHIFT_MIN+YYWILDCARD<0 | |
492 | + j>=0 && | |
493 | +#endif | |
494 | +#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT | |
495 | + j<YY_ACTTAB_COUNT && | |
496 | +#endif | |
497 | + yy_lookahead[j]==YYWILDCARD && iLookAhead>0 | |
498 | + ){ | |
381 | 499 | #ifndef NDEBUG |
382 | 500 | if( yyTraceFILE ){ |
383 | 501 | fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", |
384 | - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); | |
502 | + yyTracePrompt, yyTokenName[iLookAhead], | |
503 | + yyTokenName[YYWILDCARD]); | |
504 | + fflush(yyTraceFILE); | |
385 | 505 | } |
386 | 506 | #endif /* NDEBUG */ |
387 | 507 | return yy_action[j]; |
388 | 508 | } |
389 | 509 | } |
390 | 510 | #endif /* YYWILDCARD */ |
511 | + return yy_default[stateno]; | |
512 | + }else{ | |
513 | + return yy_action[i]; | |
391 | 514 | } |
392 | - return yy_default[stateno]; | |
393 | - }else{ | |
394 | - return yy_action[i]; | |
395 | - } | |
515 | + }while(1); | |
396 | 516 | } |
397 | 517 | |
398 | 518 | /* |
399 | 519 | ** Find the appropriate action for a parser given the non-terminal |
400 | 520 | ** look-ahead token iLookAhead. |
401 | -** | |
402 | -** If the look-ahead token is YYNOCODE, then check to see if the action is | |
403 | -** independent of the look-ahead. If it is, return the action, otherwise | |
404 | -** return YY_NO_ACTION. | |
405 | 521 | */ |
406 | 522 | static int yy_find_reduce_action( |
407 | 523 | int stateno, /* Current state number */ |
408 | 524 | YYCODETYPE iLookAhead /* The look-ahead token */ |
409 | 525 | ){ |
410 | 526 | int i; |
411 | - if( stateno>YY_REDUCE_MAX || | |
412 | - (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){ | |
413 | - return yy_default[stateno]; | |
527 | +#ifdef YYERRORSYMBOL | |
528 | + if( stateno>YY_REDUCE_COUNT ){ | |
529 | + return yy_default[stateno]; | |
414 | 530 | } |
531 | +#else | |
532 | + assert( stateno<=YY_REDUCE_COUNT ); | |
533 | +#endif | |
534 | + i = yy_reduce_ofst[stateno]; | |
415 | 535 | assert( i!=YY_REDUCE_USE_DFLT ); |
416 | 536 | assert( iLookAhead!=YYNOCODE ); |
417 | 537 | i += iLookAhead; |
418 | - if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ | |
538 | +#ifdef YYERRORSYMBOL | |
539 | + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ | |
419 | 540 | return yy_default[stateno]; |
420 | - }else{ | |
421 | - return yy_action[i]; | |
422 | 541 | } |
542 | +#else | |
543 | + assert( i>=0 && i<YY_ACTTAB_COUNT ); | |
544 | + assert( yy_lookahead[i]==iLookAhead ); | |
545 | +#endif | |
423 | 546 | return yy_action[i]; |
424 | 547 | } |
425 | 548 | |
426 | 549 | /* |
427 | 550 | ** The following routine is called if the stack overflows. |
428 | 551 | */ |
429 | -static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ | |
552 | +static void yyStackOverflow(yyParser *yypParser){ | |
430 | 553 | ParseARG_FETCH; |
431 | - yypParser->yyidx--; | |
554 | + yypParser->yytos--; | |
432 | 555 | #ifndef NDEBUG |
433 | 556 | if( yyTraceFILE ){ |
434 | 557 | fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); |
558 | + fflush(yyTraceFILE); | |
435 | 559 | } |
436 | 560 | #endif |
437 | - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); | |
561 | + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); | |
438 | 562 | /* Here code is inserted which will execute if the parser |
439 | 563 | ** stack every overflows */ |
564 | +/******** Begin %stack_overflow code ******************************************/ | |
440 | 565 | %% |
566 | +/******** End %stack_overflow code ********************************************/ | |
441 | 567 | ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ |
442 | 568 | } |
443 | 569 | |
444 | 570 | /* |
571 | +** Print tracing information for a SHIFT action | |
572 | +*/ | |
573 | +#ifndef NDEBUG | |
574 | +static void yyTraceShift(yyParser *yypParser, int yyNewState){ | |
575 | + if( yyTraceFILE ){ | |
576 | + if( yyNewState<YYNSTATE ){ | |
577 | + fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n", | |
578 | + yyTracePrompt,yyTokenName[yypParser->yytos->major], | |
579 | + yyNewState); | |
580 | + }else{ | |
581 | + fprintf(yyTraceFILE,"%sShift '%s'\n", | |
582 | + yyTracePrompt,yyTokenName[yypParser->yytos->major]); | |
583 | + } | |
584 | + fflush(yyTraceFILE); | |
585 | + } | |
586 | +} | |
587 | +#else | |
588 | +# define yyTraceShift(X,Y) | |
589 | +#endif | |
590 | + | |
591 | +/* | |
445 | 592 | ** Perform a shift action. |
446 | 593 | */ |
447 | 594 | static void yy_shift( |
448 | 595 | yyParser *yypParser, /* The parser to be shifted */ |
449 | 596 | int yyNewState, /* The new state to shift in */ |
450 | 597 | int yyMajor, /* The major token to shift in */ |
451 | - YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */ | |
598 | + ParseTOKENTYPE yyMinor /* The minor token to shift in */ | |
452 | 599 | ){ |
453 | 600 | yyStackEntry *yytos; |
454 | - yypParser->yyidx++; | |
455 | -#if YYSTACKDEPTH>0 | |
456 | - if( yypParser->yyidx>=YYSTACKDEPTH ){ | |
457 | - yyStackOverflow(yypParser, yypMinor); | |
601 | + yypParser->yytos++; | |
602 | +#ifdef YYTRACKMAXSTACKDEPTH | |
603 | + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ | |
604 | + yypParser->yyhwm++; | |
605 | + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); | |
606 | + } | |
607 | +#endif | |
608 | +#if YYSTACKDEPTH>0 | |
609 | + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ | |
610 | + yyStackOverflow(yypParser); | |
458 | 611 | return; |
459 | 612 | } |
460 | 613 | #else |
461 | - if( yypParser->yyidx>=yypParser->yystksz ){ | |
462 | - yyGrowStack(yypParser); | |
463 | - if( yypParser->yyidx>=yypParser->yystksz ){ | |
464 | - yyStackOverflow(yypParser, yypMinor); | |
614 | + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ | |
615 | + if( yyGrowStack(yypParser) ){ | |
616 | + yyStackOverflow(yypParser); | |
465 | 617 | return; |
466 | 618 | } |
467 | 619 | } |
468 | 620 | #endif |
469 | - yytos = &yypParser->yystack[yypParser->yyidx]; | |
470 | - yytos->stateno = yyNewState; | |
471 | - yytos->major = yyMajor; | |
472 | - yytos->minor = *yypMinor; | |
473 | -#ifndef NDEBUG | |
474 | - if( yyTraceFILE && yypParser->yyidx>0 ){ | |
475 | - int i; | |
476 | - fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); | |
477 | - fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); | |
478 | - for(i=1; i<=yypParser->yyidx; i++) | |
479 | - fprintf(yyTraceFILE," (%d)%s",yypParser->yystack[i].stateno,yyTokenName[yypParser->yystack[i].major]); | |
480 | - fprintf(yyTraceFILE,"\n"); | |
621 | + if( yyNewState > YY_MAX_SHIFT ){ | |
622 | + yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; | |
481 | 623 | } |
482 | -#endif | |
624 | + yytos = yypParser->yytos; | |
625 | + yytos->stateno = (YYACTIONTYPE)yyNewState; | |
626 | + yytos->major = (YYCODETYPE)yyMajor; | |
627 | + yytos->minor.yy0 = yyMinor; | |
628 | + yyTraceShift(yypParser, yyNewState); | |
483 | 629 | } |
484 | 630 | |
485 | 631 | /* The following table contains information about every rule that |
@@ -500,39 +646,48 @@ | ||
500 | 646 | */ |
501 | 647 | static void yy_reduce( |
502 | 648 | yyParser *yypParser, /* The parser */ |
503 | - int yyruleno /* Number of the rule by which to reduce */ | |
649 | + unsigned int yyruleno /* Number of the rule by which to reduce */ | |
504 | 650 | ){ |
505 | 651 | int yygoto; /* The next state */ |
506 | 652 | int yyact; /* The next action */ |
507 | - YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ | |
508 | 653 | yyStackEntry *yymsp; /* The top of the parser's stack */ |
509 | 654 | int yysize; /* Amount to pop the stack */ |
510 | 655 | ParseARG_FETCH; |
511 | - yymsp = &yypParser->yystack[yypParser->yyidx]; | |
656 | + yymsp = yypParser->yytos; | |
512 | 657 | #ifndef NDEBUG |
513 | - if( yyTraceFILE && yyruleno>=0 | |
514 | - && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ | |
515 | - fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, | |
516 | - yyRuleName[yyruleno]); | |
658 | + if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ | |
659 | + yysize = yyRuleInfo[yyruleno].nrhs; | |
660 | + fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, | |
661 | + yyRuleName[yyruleno], yymsp[-yysize].stateno); | |
662 | + fflush(yyTraceFILE); | |
517 | 663 | } |
518 | 664 | #endif /* NDEBUG */ |
519 | 665 | |
520 | - /* Silence complaints from purify about yygotominor being uninitialized | |
521 | - ** in some cases when it is copied into the stack after the following | |
522 | - ** switch. yygotominor is uninitialized when a rule reduces that does | |
523 | - ** not set the value of its left-hand side nonterminal. Leaving the | |
524 | - ** value of the nonterminal uninitialized is utterly harmless as long | |
525 | - ** as the value is never used. So really the only thing this code | |
526 | - ** accomplishes is to quieten purify. | |
527 | - ** | |
528 | - ** 2007-01-16: The wireshark project (www.wireshark.org) reports that | |
529 | - ** without this code, their parser segfaults. I'm not sure what there | |
530 | - ** parser is doing to make this happen. This is the second bug report | |
531 | - ** from wireshark this week. Clearly they are stressing Lemon in ways | |
532 | - ** that it has not been previously stressed... (SQLite ticket #2172) | |
533 | - */ | |
534 | - memset(&yygotominor, 0, sizeof(yygotominor)); | |
535 | - | |
666 | + /* Check that the stack is large enough to grow by a single entry | |
667 | + ** if the RHS of the rule is empty. This ensures that there is room | |
668 | + ** enough on the stack to push the LHS value */ | |
669 | + if( yyRuleInfo[yyruleno].nrhs==0 ){ | |
670 | +#ifdef YYTRACKMAXSTACKDEPTH | |
671 | + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ | |
672 | + yypParser->yyhwm++; | |
673 | + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); | |
674 | + } | |
675 | +#endif | |
676 | +#if YYSTACKDEPTH>0 | |
677 | + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ | |
678 | + yyStackOverflow(yypParser); | |
679 | + return; | |
680 | + } | |
681 | +#else | |
682 | + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ | |
683 | + if( yyGrowStack(yypParser) ){ | |
684 | + yyStackOverflow(yypParser); | |
685 | + return; | |
686 | + } | |
687 | + yymsp = yypParser->yytos; | |
688 | + } | |
689 | +#endif | |
690 | + } | |
536 | 691 | |
537 | 692 | switch( yyruleno ){ |
538 | 693 | /* Beginning here are the reduction cases. A typical example |
@@ -543,31 +698,26 @@ | ||
543 | 698 | ** #line <lineno> <thisfile> |
544 | 699 | ** break; |
545 | 700 | */ |
701 | +/********** Begin reduce actions **********************************************/ | |
546 | 702 | %% |
703 | +/********** End reduce actions ************************************************/ | |
547 | 704 | }; |
705 | + assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) ); | |
548 | 706 | yygoto = yyRuleInfo[yyruleno].lhs; |
549 | 707 | yysize = yyRuleInfo[yyruleno].nrhs; |
550 | - yypParser->yyidx -= yysize; | |
551 | - yyact = yy_find_reduce_action(yymsp[-yysize].stateno,yygoto); | |
552 | - if( yyact < YYNSTATE ){ | |
553 | -#ifdef NDEBUG | |
554 | - /* If we are not debugging and the reduce action popped at least | |
555 | - ** one element off the stack, then we can push the new element back | |
556 | - ** onto the stack here, and skip the stack overflow test in yy_shift(). | |
557 | - ** That gives a significant speed improvement. */ | |
558 | - if( yysize ){ | |
559 | - yypParser->yyidx++; | |
560 | - yymsp -= yysize-1; | |
561 | - yymsp->stateno = yyact; | |
562 | - yymsp->major = yygoto; | |
563 | - yymsp->minor = yygotominor; | |
564 | - }else | |
565 | -#endif | |
566 | - { | |
567 | - yy_shift(yypParser,yyact,yygoto,&yygotominor); | |
708 | + yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); | |
709 | + if( yyact <= YY_MAX_SHIFTREDUCE ){ | |
710 | + if( yyact>YY_MAX_SHIFT ){ | |
711 | + yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; | |
568 | 712 | } |
713 | + yymsp -= yysize-1; | |
714 | + yypParser->yytos = yymsp; | |
715 | + yymsp->stateno = (YYACTIONTYPE)yyact; | |
716 | + yymsp->major = (YYCODETYPE)yygoto; | |
717 | + yyTraceShift(yypParser, yyact); | |
569 | 718 | }else{ |
570 | - assert( yyact == YYNSTATE + YYNRULE + 1 ); | |
719 | + assert( yyact == YY_ACCEPT_ACTION ); | |
720 | + yypParser->yytos -= yysize; | |
571 | 721 | yy_accept(yypParser); |
572 | 722 | } |
573 | 723 | } |
@@ -575,6 +725,7 @@ | ||
575 | 725 | /* |
576 | 726 | ** The following code executes when the parse fails |
577 | 727 | */ |
728 | +#ifndef YYNOERRORRECOVERY | |
578 | 729 | static void yy_parse_failed( |
579 | 730 | yyParser *yypParser /* The parser */ |
580 | 731 | ){ |
@@ -582,14 +733,18 @@ | ||
582 | 733 | #ifndef NDEBUG |
583 | 734 | if( yyTraceFILE ){ |
584 | 735 | fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); |
736 | + fflush(yyTraceFILE); | |
585 | 737 | } |
586 | 738 | #endif |
587 | - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); | |
739 | + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); | |
588 | 740 | /* Here code is inserted which will be executed whenever the |
589 | 741 | ** parser fails */ |
742 | +/************ Begin %parse_failure code ***************************************/ | |
590 | 743 | %% |
744 | +/************ End %parse_failure code *****************************************/ | |
591 | 745 | ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ |
592 | 746 | } |
747 | +#endif /* YYNOERRORRECOVERY */ | |
593 | 748 | |
594 | 749 | /* |
595 | 750 | ** The following code executes when a syntax error first occurs. |
@@ -597,11 +752,13 @@ | ||
597 | 752 | static void yy_syntax_error( |
598 | 753 | yyParser *yypParser, /* The parser */ |
599 | 754 | int yymajor, /* The major type of the error token */ |
600 | - YYMINORTYPE yyminor /* The minor type of the error token */ | |
755 | + ParseTOKENTYPE yyminor /* The minor type of the error token */ | |
601 | 756 | ){ |
602 | 757 | ParseARG_FETCH; |
603 | -#define TOKEN (yyminor.yy0) | |
758 | +#define TOKEN yyminor | |
759 | +/************ Begin %syntax_error code ****************************************/ | |
604 | 760 | %% |
761 | +/************ End %syntax_error code ******************************************/ | |
605 | 762 | ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ |
606 | 763 | } |
607 | 764 |
@@ -615,12 +772,22 @@ | ||
615 | 772 | #ifndef NDEBUG |
616 | 773 | if( yyTraceFILE ){ |
617 | 774 | fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); |
775 | + fflush(yyTraceFILE); | |
618 | 776 | } |
619 | 777 | #endif |
620 | - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); | |
778 | +#ifndef YYNOERRORRECOVERY | |
779 | + yypParser->yyerrcnt = -1; | |
780 | +#endif | |
781 | +#if 0 | |
782 | + assert( yypParser->yytos==yypParser->yystack ); | |
783 | +#else | |
784 | + while (yypParser->yytos>yypParser->yystack) yy_pop_parser_stack(yypParser); | |
785 | +#endif | |
621 | 786 | /* Here code is inserted which will be executed whenever the |
622 | 787 | ** parser accepts */ |
788 | +/*********** Begin %parse_accept code *****************************************/ | |
623 | 789 | %% |
790 | +/*********** End %parse_accept code *******************************************/ | |
624 | 791 | ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ |
625 | 792 | } |
626 | 793 |
@@ -650,55 +817,49 @@ | ||
650 | 817 | ParseARG_PDECL /* Optional %extra_argument parameter */ |
651 | 818 | ){ |
652 | 819 | YYMINORTYPE yyminorunion; |
653 | - int yyact; /* The parser action. */ | |
820 | + unsigned int yyact; /* The parser action. */ | |
821 | +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) | |
654 | 822 | int yyendofinput; /* True if we are at the end of input */ |
823 | +#endif | |
655 | 824 | #ifdef YYERRORSYMBOL |
656 | 825 | int yyerrorhit = 0; /* True if yymajor has invoked an error */ |
657 | 826 | #endif |
658 | 827 | yyParser *yypParser; /* The parser */ |
659 | 828 | |
660 | - /* (re)initialize the parser, if necessary */ | |
661 | 829 | yypParser = (yyParser*)yyp; |
662 | - if( yypParser->yyidx<0 ){ | |
663 | -#if YYSTACKDEPTH<=0 | |
664 | - if( yypParser->yystksz <=0 ){ | |
665 | - memset(&yyminorunion, 0, sizeof(yyminorunion)); | |
666 | - yyStackOverflow(yypParser, &yyminorunion); | |
667 | - return; | |
668 | - } | |
830 | + assert( yypParser->yytos!=0 ); | |
831 | +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) | |
832 | + yyendofinput = (yymajor==0); | |
669 | 833 | #endif |
670 | - yypParser->yyidx = 0; | |
671 | - yypParser->yyerrcnt = -1; | |
672 | - yypParser->yystack[0].stateno = 0; | |
673 | - yypParser->yystack[0].major = 0; | |
674 | - } | |
675 | - yyminorunion.yy0 = yyminor; | |
676 | - yyendofinput = (yymajor==0); | |
677 | 834 | ParseARG_STORE; |
678 | 835 | |
679 | 836 | #ifndef NDEBUG |
680 | 837 | if( yyTraceFILE ){ |
681 | - fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); | |
838 | + fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]); | |
839 | + fflush(yyTraceFILE); | |
682 | 840 | } |
683 | 841 | #endif |
684 | 842 | |
685 | 843 | do{ |
686 | - yyact = yy_find_shift_action(yypParser,yymajor); | |
687 | - if( yyact<YYNSTATE ){ | |
688 | - assert( !yyendofinput ); /* Impossible to shift the $ token */ | |
689 | - yy_shift(yypParser,yyact,yymajor,&yyminorunion); | |
844 | + yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); | |
845 | + if( yyact <= YY_MAX_SHIFTREDUCE ){ | |
846 | + yy_shift(yypParser,yyact,yymajor,yyminor); | |
847 | +#ifndef YYNOERRORRECOVERY | |
690 | 848 | yypParser->yyerrcnt--; |
849 | +#endif | |
691 | 850 | yymajor = YYNOCODE; |
692 | - }else if( yyact < YYNSTATE + YYNRULE ){ | |
693 | - yy_reduce(yypParser,yyact-YYNSTATE); | |
851 | + }else if( yyact <= YY_MAX_REDUCE ){ | |
852 | + yy_reduce(yypParser,yyact-YY_MIN_REDUCE); | |
694 | 853 | }else{ |
854 | + assert( yyact == YY_ERROR_ACTION ); | |
855 | + yyminorunion.yy0 = yyminor; | |
695 | 856 | #ifdef YYERRORSYMBOL |
696 | 857 | int yymx; |
697 | 858 | #endif |
698 | - assert( yyact == YY_ERROR_ACTION ); | |
699 | 859 | #ifndef NDEBUG |
700 | 860 | if( yyTraceFILE ){ |
701 | 861 | fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); |
862 | + fflush(yyTraceFILE); | |
702 | 863 | } |
703 | 864 | #endif |
704 | 865 | #ifdef YYERRORSYMBOL |
@@ -722,40 +883,53 @@ | ||
722 | 883 | ** |
723 | 884 | */ |
724 | 885 | if( yypParser->yyerrcnt<0 ){ |
725 | - yy_syntax_error(yypParser,yymajor,yyminorunion); | |
886 | + yy_syntax_error(yypParser,yymajor,yyminor); | |
726 | 887 | } |
727 | - yymx = yypParser->yystack[yypParser->yyidx].major; | |
888 | + yymx = yypParser->yytos->major; | |
728 | 889 | if( yymx==YYERRORSYMBOL || yyerrorhit ){ |
729 | 890 | #ifndef NDEBUG |
730 | 891 | if( yyTraceFILE ){ |
731 | 892 | fprintf(yyTraceFILE,"%sDiscard input token %s\n", |
732 | 893 | yyTracePrompt,yyTokenName[yymajor]); |
894 | + fflush(yyTraceFILE); | |
733 | 895 | } |
734 | 896 | #endif |
735 | - yy_destructor(yymajor,&yyminorunion); | |
897 | + yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); | |
736 | 898 | yymajor = YYNOCODE; |
737 | 899 | }else{ |
738 | - while( | |
739 | - yypParser->yyidx >= 0 && | |
740 | - yymx != YYERRORSYMBOL && | |
741 | - (yyact = yy_find_reduce_action( | |
742 | - yypParser->yystack[yypParser->yyidx].stateno, | |
743 | - YYERRORSYMBOL)) >= YYNSTATE | |
900 | + while( yypParser->yytos >= yypParser->yystack | |
901 | + && yymx != YYERRORSYMBOL | |
902 | + && (yyact = yy_find_reduce_action( | |
903 | + yypParser->yytos->stateno, | |
904 | + YYERRORSYMBOL)) >= YY_MIN_REDUCE | |
744 | 905 | ){ |
745 | 906 | yy_pop_parser_stack(yypParser); |
746 | 907 | } |
747 | - if( yypParser->yyidx < 0 || yymajor==0 ){ | |
748 | - yy_destructor(yymajor,&yyminorunion); | |
908 | + if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ | |
909 | + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); | |
749 | 910 | yy_parse_failed(yypParser); |
911 | +#ifndef YYNOERRORRECOVERY | |
912 | + yypParser->yyerrcnt = -1; | |
913 | +#endif | |
750 | 914 | yymajor = YYNOCODE; |
751 | 915 | }else if( yymx!=YYERRORSYMBOL ){ |
752 | - YYMINORTYPE u2; | |
753 | - u2.YYERRSYMDT = 0; | |
754 | - yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); | |
916 | + yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); | |
755 | 917 | } |
756 | 918 | } |
757 | 919 | yypParser->yyerrcnt = 3; |
758 | 920 | yyerrorhit = 1; |
921 | +#elif defined(YYNOERRORRECOVERY) | |
922 | + /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to | |
923 | + ** do any kind of error recovery. Instead, simply invoke the syntax | |
924 | + ** error routine and continue going as if nothing had happened. | |
925 | + ** | |
926 | + ** Applications can set this macro (for example inside %include) if | |
927 | + ** they intend to abandon the parse upon the first syntax error seen. | |
928 | + */ | |
929 | + yy_syntax_error(yypParser,yymajor, yyminor); | |
930 | + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); | |
931 | + yymajor = YYNOCODE; | |
932 | + | |
759 | 933 | #else /* YYERRORSYMBOL is not defined */ |
760 | 934 | /* This is what we do if the grammar does not define ERROR: |
761 | 935 | ** |
@@ -767,16 +941,32 @@ | ||
767 | 941 | ** three input tokens have been successfully shifted. |
768 | 942 | */ |
769 | 943 | if( yypParser->yyerrcnt<=0 ){ |
770 | - yy_syntax_error(yypParser,yymajor,yyminorunion); | |
944 | + yy_syntax_error(yypParser,yymajor, yyminor); | |
771 | 945 | } |
772 | 946 | yypParser->yyerrcnt = 3; |
773 | - yy_destructor(yymajor,&yyminorunion); | |
947 | + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); | |
774 | 948 | if( yyendofinput ){ |
775 | 949 | yy_parse_failed(yypParser); |
950 | +#ifndef YYNOERRORRECOVERY | |
951 | + yypParser->yyerrcnt = -1; | |
952 | +#endif | |
776 | 953 | } |
777 | 954 | yymajor = YYNOCODE; |
778 | 955 | #endif |
779 | 956 | } |
780 | - }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); | |
957 | + }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); | |
958 | +#ifndef NDEBUG | |
959 | + if( yyTraceFILE ){ | |
960 | + yyStackEntry *i; | |
961 | + char cDiv = '['; | |
962 | + fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); | |
963 | + for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ | |
964 | + fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); | |
965 | + cDiv = ' '; | |
966 | + } | |
967 | + fprintf(yyTraceFILE,"]\n"); | |
968 | + fflush(yyTraceFILE); | |
969 | + } | |
970 | +#endif | |
781 | 971 | return; |
782 | 972 | } |