1#include <time.h>
2#include <stdio.h>
3#include <string.h>
4#include <stdlib.h>
5#include "tools/re2c/globals.h"
6#include "tools/re2c/parse.h"
7#include "tools/re2c/parser.h"
8
9int yylex(void);
10static RegExp *parse_expr(void);
11static RegExp *parse_diff(void);
12static RegExp *parse_term(void);
13static RegExp *parse_factor(void);
14static RegExp *parse_primary(void);
15
16static unsigned int accept;
17static RegExp *spec;
18static Scanner *in;
19
20static int curtok, peektok;
21yystype yylval;
22static yystype peekval;
23
24#define get_next_token()    (curtok = yylex())
25
26static void
27get_peek_token(void)
28{
29    yystype temp = yylval; /* structure copy */
30    if (peektok != NONE)
31	Scanner_fatal(in, "more than one token of lookahead?");
32    peektok = yylex();
33    peekval = yylval; /* structure copy */
34    yylval = temp;
35}
36
37static void
38yyparse(void)
39{
40    RegExp *re, *look;
41
42    accept = 0;
43    spec = NULL;
44    get_next_token();
45    while (curtok != 0) {
46	switch (curtok) {
47	    case ID:
48		get_peek_token();
49		if (peektok == '=') {
50		    /* ID = expr; */
51		    Symbol *sym = yylval.symbol;
52		    get_next_token(); /* id */
53		    get_next_token(); /* = */
54		    re = parse_expr();
55		    if (curtok != ';')
56			Scanner_fatal(in, "missing `;' after regexp");
57		    get_next_token(); /* ; */
58		    if (sym->re)
59			Scanner_fatal(in, "sym already defined");
60		    sym->re = re;
61		    break;
62		}
63		/*@fallthrough@*/
64	    default:
65		/* rule: expr [/ expr] CODE */
66		re = parse_expr();
67		if (!re)
68		    Scanner_fatal(in, "expression syntax error");
69
70		if (curtok == '/') {
71		    get_next_token(); /* / */
72		    look = parse_expr();
73		} else
74		    look = RegExp_new_NullOp();
75
76		if (curtok != CODE)
77		    Scanner_fatal(in, "missing code after regexp");
78		re = RegExp_new_RuleOp(re, look, yylval.token, accept++);
79		get_next_token(); /* CODE */
80		spec = spec ? mkAlt(spec, re) : re;
81	}
82    }
83}
84
85static RegExp *
86parse_expr(void)
87{
88    RegExp *e, *f;
89    e = parse_diff();
90    while (curtok == '|') {
91	get_next_token(); /* | */
92	f = parse_diff();
93	e = mkAlt(e, f);
94    }
95    return e;
96}
97
98static RegExp *
99parse_diff(void)
100{
101    RegExp *e, *f;
102    e = parse_term();
103    while (curtok == '\\') {
104	get_next_token(); /* \ */
105	f = parse_term();
106	e = mkDiff(e, f);
107	if(!e)
108	    Scanner_fatal(in, "can only difference char sets");
109    }
110    return e;
111}
112
113static RegExp *
114parse_term(void)
115{
116    RegExp *e, *f;
117    e = parse_factor();
118    while ((f = parse_factor())) {
119	e = RegExp_new_CatOp(e, f);
120    }
121    return e;
122}
123
124static RegExp *
125parse_factor(void)
126{
127    RegExp *e;
128    char ch;
129    e = parse_primary();
130    while (curtok == CLOSE || curtok == CLOSESIZE) {
131	switch (curtok) {
132	    case CLOSE:
133		ch = yylval.op;
134		while (get_next_token() == CLOSE) {
135		    if (ch != yylval.op)
136			ch = '*';
137		}
138		switch (ch) {
139		    case '*':
140			e = mkAlt(RegExp_new_CloseOp(e), RegExp_new_NullOp());
141			break;
142		    case '+':
143			e = RegExp_new_CloseOp(e);
144			break;
145		    case '?':
146			e = mkAlt(e, RegExp_new_NullOp());
147			break;
148		}
149		break;
150	    case CLOSESIZE:
151		e = RegExp_new_CloseVOp(e, yylval.extop.minsize,
152					yylval.extop.maxsize);
153		get_next_token();	/* CLOSESIZE */
154		break;
155	    default:
156		Scanner_fatal(in, "parse error");
157		break;
158	}
159    }
160    return e;
161}
162
163static RegExp *
164parse_primary(void)
165{
166    RegExp *e;
167    switch (curtok) {
168	case ID:
169	    if (!yylval.symbol->re)
170		Scanner_fatal(in, "can't find symbol");
171	    e = yylval.symbol->re;
172	    get_next_token();
173	    break;
174	case RANGE:
175	case STRING:
176	    e = yylval.regexp;
177	    get_next_token();
178	    break;
179	case '(':
180	    get_next_token();
181	    e = parse_expr();
182	    if (curtok != ')')
183		Scanner_fatal(in, "missing closing parenthesis");
184	    get_next_token();
185	    break;
186	default:
187	    return NULL;
188    }
189    return e;
190}
191
192int
193yylex(void)
194{
195    if (peektok != NONE) {
196	int tok = peektok;
197	yylval = peekval;
198	peektok = NONE;
199	return tok;
200    }
201    return Scanner_scan(in);
202}
203
204void line_source(FILE *o, unsigned int line)
205{
206    char *	fnamebuf;
207    char *	token;
208
209    if (iFlag)
210	return;
211    fprintf(o, "#line %u \"", line);
212    if( fileName != NULL ) {
213    	fnamebuf = mystrdup( fileName );
214    } else {
215	fnamebuf = mystrdup( "<stdin>" );
216    }
217    token = strtok( fnamebuf, "\\" );
218    for(;;) {
219	fprintf(o, "%s", token);
220	token = strtok( NULL, "\\" );
221	if( token == NULL ) break;
222	fputs("\\\\", o);
223    }
224    fputs("\"\n", o); oline++;
225    free( fnamebuf );
226}
227
228void parse(FILE *i, FILE *o){
229    time_t now;
230
231    time(&now);
232
233    peektok = NONE;
234
235    fputs("/* Generated by re2c 0.9.1-C on ", o);
236    fprintf(o, "%-24s", ctime(&now));
237    fputs(" */\n", o); oline+=2;
238
239    in = Scanner_new(i);
240
241    line_source(o, Scanner_line(in));
242
243    while(Scanner_echo(in, o)){
244	yyparse();
245	if(spec)
246	    genCode(o, spec);
247	line_source(o, Scanner_line(in));
248    }
249}
250