Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * Copyright 2005 Sun Microsystems, Inc. All rights reserved. | |
3 | * Use is subject to license terms. | |
4 | */ | |
5 | ||
6 | ||
7 | %{ | |
8 | ||
9 | #pragma ident "@(#)mdlex.l 1.3 05/11/03 SMI" | |
10 | ||
11 | /* any C includes here */ | |
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | #include <unistd.h> | |
15 | #include <string.h> | |
16 | #include <stdarg.h> | |
17 | #include <errno.h> | |
18 | ||
19 | #include "basics.h" | |
20 | #include "allocate.h" | |
21 | #include "lexer.h" | |
22 | #include "fatal.h" | |
23 | ||
24 | lexer_t lex; /* additional return value info */ | |
25 | #define MAX_STR_LEN (1024+1) | |
26 | static struct { | |
27 | char base[MAX_STR_LEN]; | |
28 | char * ptr; | |
29 | } sbuffer; | |
30 | ||
31 | #if TESTRIG /* { */ | |
32 | #include <stdarg.h> | |
33 | #include <errno.h> | |
34 | void fatal(char *s,...); | |
35 | #endif /* } */ | |
36 | ||
37 | #define SBUFFER_INS(_c) do { \ | |
38 | if ((sbuffer.ptr - sbuffer.base)>=MAX_STR_LEN) \ | |
39 | lex_fatal("Parse string too long - maximum is %d characters", MAX_STR_LEN); \ | |
40 | *sbuffer.ptr++ = (_c); \ | |
41 | } while(0) | |
42 | %} | |
43 | ||
44 | DECNUM ("0"|([1-9][0-9]*)) | |
45 | ||
46 | %x comment | |
47 | %x string | |
48 | ||
49 | %% | |
50 | ||
51 | <<EOF>> return T_EOF; | |
52 | ||
53 | "{" return T_L_Brace; | |
54 | ||
55 | "}" return T_R_Brace; | |
56 | ||
57 | ")" return T_R_Bracket; | |
58 | ||
59 | "," return T_Comma; | |
60 | ||
61 | ";" return T_S_Colon; | |
62 | ||
63 | "+" return T_Plus; | |
64 | ||
65 | "*" return T_Multiply; | |
66 | ||
67 | "-" return T_Minus; | |
68 | ||
69 | "&" return T_And; | |
70 | ||
71 | "|" return T_Or; | |
72 | ||
73 | "^" return T_Xor; | |
74 | ||
75 | "~" return T_Not; | |
76 | ||
77 | "<<" return T_LShift; | |
78 | ||
79 | "=" return T_Equals; | |
80 | ||
81 | "]" return T_R_Bracket; | |
82 | ||
83 | "[" return T_L_Bracket; | |
84 | ||
85 | ^"#"[ \t].*$ { | |
86 | char lbuf[1024]; | |
87 | int num; | |
88 | if (sscanf(mdlextext,"# %d \"%[^\"]\"", &num, lbuf)!=2) | |
89 | lex_fatal("Illegal # directive"); | |
90 | lex.linenum = num-1; | |
91 | if (lex.fnamep != (char*)0) Xfree(lex.fnamep); | |
92 | lex.fnamep = Xstrdup(lbuf); | |
93 | } | |
94 | ||
95 | "node" return T_KW_node; | |
96 | ||
97 | "proto" return T_KW_proto; | |
98 | ||
99 | "include" return T_KW_include; | |
100 | ||
101 | "(" return T_KW_expr; | |
102 | ||
103 | "expr(" return T_KW_expr; | |
104 | ||
105 | "lookup(" return T_KW_lookup; | |
106 | ||
107 | "setprop(" return T_KW_setprop; | |
108 | ||
109 | "->" return T_KW_arc; | |
110 | ||
111 | ||
112 | \" { | |
113 | sbuffer.ptr = sbuffer.base; | |
114 | BEGIN(string); | |
115 | } | |
116 | ||
117 | <string>\" { /* closing quote - wrap up string and return it */ | |
118 | BEGIN(INITIAL); | |
119 | sbuffer.ptr[0]='\0'; | |
120 | lex.strp = sbuffer.base; | |
121 | return T_String; | |
122 | } | |
123 | ||
124 | <string>\n { | |
125 | lex_fatal("unterminated string"); | |
126 | } | |
127 | ||
128 | <string>\\[0-7]{1,3} { | |
129 | /* octal escape sequence */ | |
130 | int result; | |
131 | ||
132 | result=-1; | |
133 | (void) sscanf( mdlextext + 1, "%o", &result ); | |
134 | ||
135 | if ( result<0 || result>0xff ) | |
136 | lex_fatal("error, constant is out-of-bounds"); | |
137 | ||
138 | SBUFFER_INS( result ); | |
139 | } | |
140 | ||
141 | <string>\\[0-9]+ { | |
142 | lex_fatal("illegal escape sequence"); | |
143 | } | |
144 | ||
145 | <string>\\n SBUFFER_INS( '\n' ); | |
146 | <string>\\t SBUFFER_INS( '\t' ); | |
147 | <string>\\r SBUFFER_INS( '\r' ); | |
148 | <string>\\b SBUFFER_INS( '\b' ); | |
149 | <string>\\f SBUFFER_INS( '\f' ); | |
150 | ||
151 | <string>\\(.|\n) SBUFFER_INS( mdlextext[1] ); | |
152 | ||
153 | <string>[^\\\n\"]+ { | |
154 | char *iptr = mdlextext; | |
155 | ||
156 | while ( *iptr ) SBUFFER_INS( *iptr++ ); | |
157 | } | |
158 | ||
159 | ||
160 | ||
161 | ||
162 | "0x"[0-9A-F][0-9A-F]* { | |
163 | lex.val = strtoull(mdlextext, (char **)NULL, 16); | |
164 | return T_Number; | |
165 | } | |
166 | ||
167 | "0x"[0-9a-f][0-9a-f]* { | |
168 | lex.val = strtoull(mdlextext, (char **)NULL, 16); | |
169 | ||
170 | return T_Number; | |
171 | } | |
172 | ||
173 | {DECNUM}[KkMmGg] { | |
174 | char * ep; | |
175 | lex.val = strtoll(mdlextext, &ep, 10); | |
176 | switch(*ep) { | |
177 | case 'G': case 'g': | |
178 | lex.val <<= 30; | |
179 | break; | |
180 | case 'M': case 'm': | |
181 | lex.val <<= 20; | |
182 | break; | |
183 | case 'K': case 'k': | |
184 | lex.val <<= 10; | |
185 | break; | |
186 | default: | |
187 | lex_fatal("parsing number"); | |
188 | } | |
189 | return T_Number; | |
190 | } | |
191 | ||
192 | {DECNUM} { | |
193 | lex.val = atoll(mdlextext); | |
194 | return T_Number; | |
195 | } | |
196 | ||
197 | \-{DECNUM} { | |
198 | lex.val = atoll(mdlextext); | |
199 | return T_Number; | |
200 | } | |
201 | ||
202 | ||
203 | [A-Za-z_#?$][A-Za-z_#\-?$0-9]* { | |
204 | lex.strp = mdlextext; | |
205 | return T_Token; | |
206 | } | |
207 | ||
208 | /* Note: . = any character EXCEPT newline */ | |
209 | \/\/.* { /* nada - swallow single line comments */ } | |
210 | ||
211 | [\t ]* { /* nada - swallow white space */ } | |
212 | ||
213 | ||
214 | "\n" { | |
215 | lex.linenum ++; | |
216 | } | |
217 | ||
218 | . { | |
219 | lex_fatal("Illegal character %s", mdlextext); | |
220 | } | |
221 | ||
222 | %% | |
223 | ||
224 | ||
225 | ||
226 | ||
227 | ||
228 | ||
229 | ||
230 | void init_lexer(char * fnamep, FILE *fp, char * cleanup_filep) | |
231 | { | |
232 | lex.cleanup_filep = cleanup_filep ? Xstrdup(cleanup_filep) : (char*)0; | |
233 | lex.linenum = 1; | |
234 | lex.fnamep = Xstrdup(fnamep); | |
235 | ||
236 | lex.ungot_available = false; | |
237 | lex.last_token = T_Error; | |
238 | ||
239 | mdlexin = fp; | |
240 | } | |
241 | ||
242 | ||
243 | lexer_tok_t lex_get_token() | |
244 | { | |
245 | if (lex.ungot_available) { | |
246 | lex.ungot_available = false; | |
247 | return lex.last_token; | |
248 | } | |
249 | ||
250 | lex.last_token = mdlexlex(); | |
251 | ||
252 | return lex.last_token; | |
253 | } | |
254 | ||
255 | ||
256 | ||
257 | void lex_unget() | |
258 | { | |
259 | if (lex.ungot_available) fatal("Internal error, lex_unget with token already ungot"); | |
260 | ||
261 | lex.ungot_available = true; | |
262 | } | |
263 | ||
264 | ||
265 | void lex_get(lexer_tok_t expected) | |
266 | { | |
267 | lexer_tok_t tok; | |
268 | char *s; | |
269 | char buffer[1024]; | |
270 | ||
271 | tok = lex_get_token(); | |
272 | ||
273 | if (tok == expected) return; | |
274 | ||
275 | switch(tok) { | |
276 | case T_EOF: s="end of file"; break; | |
277 | case T_L_Brace: s="{"; break; | |
278 | case T_R_Brace: s="}"; break; | |
279 | case T_S_Colon: s=";"; break; | |
280 | case T_Plus: s="+"; break; | |
281 | case T_Minus: s="-"; break; | |
282 | case T_Equals: s="="; break; | |
283 | case T_Number: s="number"; break; | |
284 | case T_String: s="string"; break; | |
285 | case T_Token: | |
286 | sprintf(buffer,"token %s", lex.strp); | |
287 | s=buffer; | |
288 | break; | |
289 | case T_KW_node: s="node"; break; | |
290 | case T_KW_proto: s="proto"; break; | |
291 | case T_KW_include: s="include("; break; | |
292 | case T_KW_expr: s="expr("; break; | |
293 | case T_KW_lookup: s="lookup("; break; | |
294 | case T_KW_setprop: s="setprop("; break; | |
295 | ||
296 | case T_Error: s="error"; break; | |
297 | default: | |
298 | s="unknown token - internal error"; | |
299 | break; | |
300 | } | |
301 | ||
302 | lex_fatal("unexpected %s", s); | |
303 | } | |
304 | ||
305 | ||
306 | /* | |
307 | * Special version of fatal for the lexer | |
308 | * to enable cleanup of stuff before death | |
309 | */ | |
310 | void | |
311 | lex_fatal(char * fmt, ...) | |
312 | { | |
313 | va_list args; | |
314 | ||
315 | if (errno != 0) | |
316 | perror("FATAL: "); | |
317 | else | |
318 | fprintf(stderr,"FATAL: "); | |
319 | if (fmt) { | |
320 | va_start(args, fmt); | |
321 | (void) vfprintf(stderr, fmt, args); | |
322 | ||
323 | va_end(args); | |
324 | } | |
325 | ||
326 | if (lex.cleanup_filep != (char *)0) { | |
327 | unlink(lex.cleanup_filep); | |
328 | Xfree(lex.cleanup_filep); | |
329 | } | |
330 | fprintf(stderr," at line %d of %s\n", lex.linenum, lex.fnamep); | |
331 | Xfree(lex.fnamep); | |
332 | ||
333 | SANITY( lex.fnamep = NULL; ); | |
334 | SANITY( lex.cleanup_filep = NULL; ); | |
335 | exit(1); | |
336 | } | |
337 | ||
338 | ||
339 | ||
340 | int | |
341 | mdlexwrap(void) | |
342 | { | |
343 | return (1); | |
344 | } | |
345 | ||
346 | #if TESTRIG /* { */ | |
347 | main() | |
348 | { | |
349 | lexer_tok_t tok; | |
350 | ||
351 | lex.linenum = 1; | |
352 | lex.fnamep = "test"; | |
353 | ||
354 | do { | |
355 | tok = lexlex(); | |
356 | ||
357 | fprintf(stderr,"token = %d at line %d in %s\n",tok, lex.linenum, lex.fnamep); | |
358 | } while (tok!=T_Error && tok!=T_EOF); | |
359 | } | |
360 | ||
361 | ||
362 | void fatal(char* fmt, ...) | |
363 | { | |
364 | va_list args; | |
365 | int status; | |
366 | ||
367 | if (errno!=0) perror("FATAL: "); else fprintf(stderr,"FATAL: "); | |
368 | if (fmt) { | |
369 | va_start(args, fmt); | |
370 | (void)vfprintf(stderr, fmt, args); | |
371 | ||
372 | va_end(args); | |
373 | } | |
374 | ||
375 | fprintf(stderr,"\n"); | |
376 | fflush(stderr); | |
377 | fflush(stdout); | |
378 | ||
379 | thr_exit(&status); | |
380 | } | |
381 | ||
382 | #endif /* } */ |