filename | src/tools/mdparse.c |
changeset | 1105:73da8fd129fb |
prev | 1104:700e16c321e5 |
next | 1296:30ecee61f811 |
author | nkeynes |
date | Fri Sep 10 08:50:55 2010 +1000 (13 years ago) |
permissions | -rw-r--r-- |
last change | Add missing sh4_translate_breakpoint_hit to the symbol table Change asm() to __asm__() as it's more likely to work |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * genmmio I/O register definition parser.
5 *
6 * Copyright (c) 2010 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <sys/stat.h>
28 #include <glib/gmem.h>
30 #include "genmach.h"
31 /*
32 * Grammar:
33 *
34 * start: start register_block | ;
35 * register_block: 'registers' IDENTIFIER 'at' INTEGER opt_paramlist '{' register_list '}';
36 * opt_paramlist: '(' param_list ')' | '(' ')' | ;
37 * param_list: param_list ',' param | param ;
38 * param: access_param | fill_param | endian_param | mask_param ;
39 * access_param: 'access' '=' 'any' // Behaves as if it were memory
40 * | 'access' '=' 'nooffset' // Recognize any size access (zero-ext or trunc) as long as the address is exactly the same
41 * | 'access' '=' 'exact' // Recognize only the exact access type at the exact address
42 * ;
43 * fill_param: 'fill' '=' literal;
44 * endian_param: 'endian' '=' 'little'
45 * | 'endian' '=' 'big'
46 * ;
47 * mask_param: 'mask' '=' literal;
48 *
49 * register_list: register_list register_desc | ;
50 * register_desc: INTEGER ':' mode_spec type_spec IDENTIFIER opt_paramlist [ '=' literal ] [ ACTION ]
51 * mode_spec: 'const' | 'rw' | 'ro' | 'wo';
52 * type_spec: 'i8' | 'i16' | 'i32' | 'i64' | 'f32' | 'f64' | 'string' | 'cstring';
53 * literal: INTEGER | STRING | 'undefined' ;
54 *
55 * C-style comments are recognized as such.
56 */
58 #define TOK_IDENTIFIER 1
59 #define TOK_INTEGER 2
60 #define TOK_STRING 3
61 #define TOK_ACTION 4
62 #define TOK_EOF 5
63 #define TOK_ERROR 6
64 #define TOK_LPAREN 7
65 #define TOK_RPAREN 8
66 #define TOK_LBRACE 9
67 #define TOK_RBRACE 10
68 #define TOK_COMMA 11
69 #define TOK_COLON 12
70 #define TOK_SEMI 13
71 #define TOK_PERIOD 14
72 #define TOK_RANGE 15
73 #define TOK_LSQUARE 16
74 #define TOK_RSQUARE 17
75 #define TOK_EQUALS 18
76 #define TOK_ACCESS 19
77 #define TOK_AT 20
78 #define TOK_ENDIAN 21
79 #define TOK_FILL 22
80 #define TOK_INCLUDE 23
81 #define TOK_MASK 24
82 #define TOK_REGISTERS 25
83 #define TOK_SPACE 26
84 #define TOK_STRIDE 27
85 #define TOK_TEST 28
86 #define TOK_TRACE 29
87 #define TOK_UNDEFINED 30
90 #define FIRST_KEYWORD TOK_ACCESS
91 #define LAST_KEYWORD TOK_UNDEFINED
92 static const char *TOKEN_NAMES[] = {"NULL", "IDENTIFIER", "INTEGER", "STRING", "ACTION", "EOF", "ERROR",
93 "(", ")", "{", "}", ",", ":", ";", ".", "..", "[", "]", "=",
94 "ACCESS", "AT", "ENDIAN", "FILL", "INCLUDE", "MASK", "REGISTERS", "SPACE", "STRIDE", "TEST", "TRACE", "UNDEFINED" };
95 static const char *MODE_NAMES[] = {"const", "rw", "ro", "wo", "mirror"};
96 static const char *TYPE_NAMES[] = {"i8", "i16", "i32", "i64", "f32", "f64", "string"};
97 static int TYPE_SIZES[] = {1,2,4,8,4,8,0};
98 static const char *ENDIAN_NAMES[] = {"default", "little", "big"};
99 static const char *ACCESS_NAMES[] = {"default", "any", "nooffset", "exact"};
100 static const char *TRACE_NAMES[] = {"default", "off", "on"};
102 #define elementsof(x) (sizeof(x)/sizeof(x[0]))
104 typedef struct token_data {
105 char *yytext;
106 int yylength;
107 int yyline;
108 int yycol;
109 union {
110 long i;
111 char *s;
112 } v;
113 int slen;
114 } token_data;
116 struct yystate {
117 char *yybuffer;
118 char *yyfilename;
119 char *yyposn, *yylineposn, *yyend;
120 int yylineno;
121 };
123 static GList *yyfile_stack = NULL;
124 static struct yystate yystate;
125 static struct token_data yytok;
127 #define YYPARSE_ERROR( msg, ... ) \
128 do { \
129 fprintf( stderr, "Parse error in %s:%d:%d: " msg "\n", yystate.yyfilename, yytok.yyline, yytok.yycol, __VA_ARGS__ ); \
130 exit(2); \
131 } while(0)
133 #define READ(x) \
134 { int _tok = iolex(x); \
135 if( _tok != (x) ) { \
136 YYPARSE_ERROR( "Expected %s but got %s", TOKEN_NAMES[x], TOKEN_NAMES[_tok] ); \
137 } \
138 }
140 static int iolex( int expectToken );
141 static int iolex_open( const char *filename );
142 static void iolex_close();
143 static int iolex_push( const char *filename );
144 static int iolex_pop( );
146 static inline char *yystrdup()
147 {
148 char *str = g_malloc0(yytok.yylength+1);
149 memcpy( str, yytok.yytext, yytok.yylength);
150 return str;
151 }
153 static inline int yystrcasecmp(const char *cmp)
154 {
155 int len = strlen(cmp);
156 if( len != yytok.yylength ) {
157 return yytok.yylength - len;
158 }
159 return strncasecmp(yytok.yytext, cmp, yytok.yylength);
160 }
162 static int yymatch( const char *arr[], unsigned numOptions )
163 {
164 for( unsigned i=0; i<numOptions; i++ ) {
165 if( yystrcasecmp( arr[i] ) == 0 ) {
166 return i;
167 }
168 }
169 return -1;
170 }
172 static gint register_block_sort_cb( gconstpointer a, gconstpointer b )
173 {
174 struct regblock *blocka = (struct regblock *)a;
175 struct regblock *blockb = (struct regblock *)b;
176 return blocka->address - blockb->address;
177 }
179 static int register_ptr_sort_cb( const void *a, const void *b )
180 {
181 regdef_t *ptra = (regdef_t *)a;
182 regdef_t *ptrb = (regdef_t *)b;
183 if( (*ptra)->offset != (*ptrb)->offset )
184 return (*ptra)->offset - (*ptrb)->offset;
185 return (*ptra)->type - (*ptrb)->type;
186 }
188 static void ioparse_apval(int tok, union apval *apv, unsigned *numBytes)
189 {
190 if( tok == TOK_INTEGER ) {
191 apv->i = yytok.v.i;
192 if( *numBytes == 0 ) {
193 YYPARSE_ERROR( "Expected string initializer but was an integer (0x%x)", yytok.v.i );
194 }
195 } else if( tok = TOK_STRING ) {
196 if( *numBytes == 0 ) {
197 *numBytes = yytok.slen;
198 apv->s = yytok.v.s;
199 } else {
200 if( *numBytes != yytok.slen ) {
201 YYPARSE_ERROR( "Expected %d byte initializer but was %d", *numBytes, yytok.slen );
202 }
203 assert( *numBytes < sizeof(uint64_t) );
204 apv->i = 0;
205 /* FIXME: handle endian mismatches */
206 memcpy( &apv->i, yytok.v.s, yytok.slen );
207 }
208 } else {
209 YYPARSE_ERROR( "Expected literal (integer or string), but got %s", TOKEN_NAMES[tok] );
210 }
211 }
213 static void ioparse_regflags( regflags_t flags, unsigned *numBytes )
214 {
215 do {
216 int tok = iolex(TOK_RPAREN);
217 switch(tok) {
218 case TOK_FILL:
219 READ(TOK_EQUALS);
220 tok = iolex(TOK_INTEGER);
221 flags->fillSizeBytes = 4;
222 ioparse_apval( tok, &flags->fillValue, &flags->fillSizeBytes );
223 break;
224 case TOK_ACCESS:
225 READ(TOK_EQUALS);
226 READ(TOK_IDENTIFIER);
227 flags->access = yymatch(ACCESS_NAMES,elementsof(ACCESS_NAMES));
228 if( flags->access == -1 ) {
229 YYPARSE_ERROR("Unknown access mode '%s'", yystrdup());
230 }
231 break;
232 case TOK_MASK:
233 if( numBytes ) {
234 READ(TOK_EQUALS);
235 tok = iolex(TOK_INTEGER);
236 ioparse_apval( tok, &flags->maskValue, numBytes );
237 } else {
238 YYPARSE_ERROR("mask is not valid on a register block",0);
239 }
240 break;
241 case TOK_ENDIAN:
242 READ(TOK_EQUALS);
243 READ(TOK_IDENTIFIER);
244 flags->endian = yymatch(ENDIAN_NAMES,elementsof(ENDIAN_NAMES));
245 if( flags->endian == -1 ) {
246 YYPARSE_ERROR("Unknown endianness '%s'", yystrdup());
247 }
248 break;
249 case TOK_TRACE:
250 READ(TOK_EQUALS);
251 READ(TOK_IDENTIFIER);
252 flags->traceFlag = yymatch(TRACE_NAMES,elementsof(TRACE_NAMES));
253 if( flags->traceFlag == -1 ) {
254 YYPARSE_ERROR("Unknown trace flag '%s'", yystrdup());
255 }
256 break;
257 case TOK_TEST:
258 READ(TOK_EQUALS);
259 READ(TOK_IDENTIFIER);
260 flags->testFlag = yymatch(TRACE_NAMES,elementsof(TRACE_NAMES));
261 if( flags->testFlag == -1 ) {
262 YYPARSE_ERROR("Unknown test flag '%s'", yystrdup());
263 }
264 break;
265 case TOK_COMMA:
266 break;
267 case TOK_RPAREN:
268 return;
269 default:
270 YYPARSE_ERROR("Expected flag or ')' but was %s", TOKEN_NAMES[tok]);
271 }
272 } while(1);
273 }
275 static void ioparse_regdef( struct regdef *reg )
276 {
277 reg->offset = yytok.v.i;
278 reg->numElements = 1;
279 reg->numBytes = 0;
280 reg->initValue.i = 0;
281 reg->flags.maskValue.i = -1;
282 unsigned rangeOffset = reg->offset;
284 int tok = iolex(TOK_COLON);
285 if( tok == TOK_RANGE ) {
286 READ(TOK_INTEGER);
287 rangeOffset = yytok.v.i;
288 if( rangeOffset < reg->offset ) {
289 YYPARSE_ERROR( "Range end (0x%x) must be greater than the range start (0x%x)", rangeOffset, reg->offset );
290 }
291 READ(TOK_COLON);
292 } else if( tok != TOK_COLON ) {
293 YYPARSE_ERROR( "Expected ':' but was %s\n", TOKEN_NAMES[tok] );
294 }
295 READ(TOK_IDENTIFIER);
296 reg->mode = yymatch(MODE_NAMES, elementsof(MODE_NAMES));
297 if( reg->mode == -1 ) {
298 YYPARSE_ERROR( "Unknown register mode '%s'", yystrdup() );
299 }
300 if( reg->mode == REG_MIRROR ) {
301 /* Mirror regions have a target range only */
302 READ(TOK_INTEGER);
303 reg->initValue.i = yytok.v.i;
304 reg->type = REG_I8;
305 tok = iolex(TOK_RANGE);
306 if( tok == TOK_RANGE ) {
307 READ(TOK_INTEGER);
308 if( yytok.v.i < reg->initValue.i ) {
309 YYPARSE_ERROR( "Invalid mirror target range 0x%x..0x%x", reg->initValue.i, yytok.v.i );
310 }
311 reg->numBytes = yytok.v.i - reg->initValue.i + 1;
312 tok = iolex(TOK_STRIDE);
313 }
314 if( tok == TOK_STRIDE ) {
315 READ(TOK_INTEGER);
316 reg->stride = yytok.v.i;
317 tok = iolex(TOK_ACTION);
318 } else {
319 reg->stride = reg->numBytes;
320 }
322 if( tok != TOK_SEMI ) {
323 YYPARSE_ERROR( "Expected ; but gut %s", TOKEN_NAMES[tok] );
324 }
326 if( reg->stride < reg->numBytes ) {
327 YYPARSE_ERROR( "Invalid mirror stride: %x is less than block size %x\n", reg->stride, reg->numBytes );
328 }
330 if( rangeOffset != reg->offset ) {
331 reg->numElements *= ((rangeOffset - reg->offset) + reg->stride - 1) / reg->stride;
332 }
334 } else {
335 READ(TOK_IDENTIFIER);
336 reg->type = yymatch(TYPE_NAMES, elementsof(TYPE_NAMES));
337 if( reg->type == -1 ) {
338 YYPARSE_ERROR( "Unknown register type '%s'", yystrdup() );
339 }
340 reg->numBytes = TYPE_SIZES[reg->type];
341 tok = iolex(TOK_IDENTIFIER);
342 if( tok == TOK_IDENTIFIER ) {
343 reg->name = yystrdup();
344 tok = iolex(TOK_ACTION);
345 }
346 if( tok == TOK_STRING ) {
347 reg->description = yytok.v.s;
348 tok = iolex(TOK_ACTION);
349 }
350 if( tok == TOK_LPAREN ) {
351 ioparse_regflags(®->flags, ®->numBytes);
352 tok = iolex(TOK_ACTION);
353 }
354 if( tok == TOK_EQUALS ) {
355 tok = iolex(TOK_INTEGER);
356 if( tok == TOK_UNDEFINED ) {
357 reg->initValue.i = 0xDEADBEEFDEADBEEF;
358 reg->initUndefined = TRUE;
359 } else {
360 ioparse_apval(tok, ®->initValue, ®->numBytes);
361 }
362 tok = iolex(TOK_ACTION);
363 } else if( reg->type == REG_STRING ) {
364 YYPARSE_ERROR( "String declarations must have an initializer (ie = 'abcd')",0 );
365 }
366 if( tok == TOK_ACTION ) {
367 // reg->action = yystrdup();
368 } else if( tok != TOK_SEMI ) {
369 YYPARSE_ERROR( "Expected ; or {, but got %s", TOKEN_NAMES[tok] );
370 }
372 if( rangeOffset != reg->offset ) {
373 reg->numElements *= ((rangeOffset - reg->offset) + reg->numBytes - 1) / reg->numBytes;
374 }
375 }
377 }
379 static struct regblock *ioparse_regblock( )
380 {
381 unsigned regsAllocSize = 128;
382 struct regblock *block = g_malloc0(sizeof(struct regblock) + sizeof(regdef_t)*regsAllocSize);
383 block->numRegs = 0;
385 READ(TOK_IDENTIFIER);
386 block->name = yystrdup();
387 int tok = iolex(TOK_AT);
388 if( tok == TOK_STRING ) {
389 block->description = yytok.v.s;
390 tok = iolex(TOK_AT);
391 }
392 if( tok != TOK_AT ) {
393 YYPARSE_ERROR("Expected AT but got %s\n", TOKEN_NAMES[tok] );
394 }
395 READ(TOK_INTEGER);
396 block->address = yytok.v.i;
398 tok = iolex(TOK_LBRACE);
399 if( tok == TOK_LPAREN) {
400 ioparse_regflags(&block->flags, NULL);
401 READ(TOK_LBRACE);
402 } else if( tok != TOK_LBRACE ) {
403 YYPARSE_ERROR("Expected { but got %s\n", TOKEN_NAMES[tok] );
404 }
406 tok = iolex(TOK_INTEGER);
407 while( tok != TOK_RBRACE ) {
408 if( tok != TOK_INTEGER ) {
409 YYPARSE_ERROR("Expected INTEGER or } but got %s\n", TOKEN_NAMES[tok]);
410 }
411 struct regdef *regdef = g_malloc0(sizeof(struct regdef));
412 if( block->numRegs >= regsAllocSize ) {
413 regsAllocSize *= 2;
414 block = g_realloc(block, sizeof(struct regblock) + sizeof(regdef_t)*regsAllocSize);
415 }
416 block->regs[block->numRegs++] = regdef;
417 ioparse_regdef(regdef);
419 tok = iolex(TOK_INTEGER);
420 }
422 qsort( &block->regs[0], block->numRegs, sizeof(block->regs[0]), register_ptr_sort_cb );
424 return block;
425 }
427 GList *ioparse( const char *filename, GList *list )
428 {
429 GList *blocks = list;
430 int count = 0;
432 if( iolex_open(filename) != 0 )
433 return blocks;
435 int tok;
436 while(1) {
437 tok = iolex(TOK_REGISTERS);
438 if( tok == TOK_EOF ) {
439 int result = iolex_pop();
440 if( result == -1 )
441 break;
442 } else if( tok == TOK_INCLUDE) {
443 READ(TOK_STRING);
444 char *tmp = yystrdup();
445 READ(TOK_SEMI);
446 int result = iolex_push( tmp );
447 if( result == -1 ) {
448 YYPARSE_ERROR("Unable to include file '%s'", tmp);
449 }
450 free(tmp);
451 } else if( tok == TOK_SPACE ) {
452 } else if( tok == TOK_REGISTERS ) {
453 struct regblock *block = ioparse_regblock(block);
454 count++;
455 blocks = g_list_insert_sorted(blocks, block, register_block_sort_cb);
456 } else {
457 YYPARSE_ERROR("Expected REGISTERS but got %s\n", TOKEN_NAMES[tok] );
458 }
459 }
460 return blocks;
461 }
463 /**************************** Lexical analyser ***************************/
465 static int iolex_push( const char *filename )
466 {
467 struct yystate *save = g_malloc(sizeof(struct yystate));
468 memcpy( save, &yystate, sizeof(struct yystate) );
470 int result = iolex_open(filename);
471 if( result == 0 ) {
472 yyfile_stack = g_list_prepend(yyfile_stack, save);
473 }
474 return result;
475 }
477 static int iolex_pop( )
478 {
479 iolex_close();
480 if( yyfile_stack == NULL )
481 return -1;
482 struct yystate *top = (struct yystate *)yyfile_stack->data;
483 yyfile_stack = g_list_remove(yyfile_stack, top);
484 memcpy( &yystate, top, sizeof(struct yystate) );
485 g_free( top );
486 return 0;
487 }
489 static int iolex_open( const char *filename )
490 {
491 struct stat st;
492 int fd = open( filename, O_RDONLY );
493 if( fd == -1 ) {
494 fprintf( stderr, "Error opening file '%s': %s\n", filename, strerror(errno) );
495 return -1;
496 }
498 if( fstat( fd, &st ) != 0 ) {
499 fprintf( stderr, "Error statting file '%s': %s\n", filename, strerror(errno) );
500 close(fd);
501 return -1;
502 }
504 char *data = g_malloc( st.st_size + 1 );
505 if( read(fd, data, st.st_size) != st.st_size ) {
506 fprintf( stderr, "Error reading file '%s': %s\n", filename, strerror(errno) );
507 close(fd);
508 return -1;
509 }
510 close(fd);
511 data[st.st_size] = 0;
513 yystate.yybuffer = yystate.yyposn = data;
514 yystate.yyend = data + st.st_size;
515 yystate.yylineno = 1;
516 yystate.yylineposn = yystate.yyposn;
517 yystate.yyfilename = strdup(filename);
518 return 0;
519 }
521 static void iolex_close()
522 {
523 g_free(yystate.yybuffer);
524 free(yystate.yyfilename);
525 memset(&yystate, 0, sizeof(struct yystate));
526 }
528 #define YYRETURN(x) do{ \
529 yytok.yylength = yystate.yyposn - yystart; \
530 return (x); \
531 } while(0)
533 static int iolex_readhex(char *p, int digits)
534 {
535 int result = 0;
536 for( int i=0; i < digits; i++ ) {
537 result <<= 4;
538 if( isdigit(p[i]) ) {
539 result += p[i]-'0';
540 } else if( p[i] >= 'a' && p[i] <= 'f' ) {
541 result += p[i]-'a'+10;
542 } else if( p[i] >= 'A' && p[i] <= 'F' ) {
543 result += p[i]-'A'+10;
544 } else {
545 return (result >> 4);
546 }
548 }
549 return result;
550 }
552 static int iolex_readoctal(char *p, int digits)
553 {
554 int result = 0;
555 for( int i=0; i < digits; i++ ) {
556 result <<= 3;
557 if( p[i] >= '0' && p[i] <= '7' ) {
558 result += p[i]-'0';
559 } else {
560 return (result >> 4);
561 }
562 }
563 return result;
564 }
566 /**
567 * Copy and interpret the string segment as a C string, replacing escape
568 * expressions with the corresponding value.
569 */
570 static char *iolex_getcstring( char *start, char *end, int *len )
571 {
572 char *result = g_malloc0(end-start+1); /* Allocate enough memory for the string as-is */
573 char *q = result;
575 for( char *p = start; p != end; p++ ) {
576 if( *p == '\\' ) {
577 if( ++p == end ) {
578 *q++ = '\\';
579 break;
580 }
581 if( p[0] >= '0' && p[0] <= '3' && p+3 <= end &&
582 p[1] >= '0' && p[1] <= '7' &&
583 p[2] >= '0' && p[2] <= '7' ) {
584 *q++ = (char)iolex_readoctal(p,3);
585 p+=2;
586 } else {
587 switch( *p ) {
588 case 'n':
589 *q++ = '\n';
590 break;
591 case 'r':
592 *q++ = '\r';
593 break;
594 case 't':
595 *q++ = '\t';
596 break;
597 case 'x': /* hex */
598 if( p + 3 > end || !isxdigit(p[1]) || !isxdigit(p[2]) ) {
599 *q++ = '\\';
600 *q++ = *p;
601 } else {
602 *q++ = (char)iolex_readhex(p+1, 2);
603 p+=2;
604 }
605 break;
606 default:
607 *q++ = '\\';
608 *q++ = *p;
609 }
610 }
611 } else {
612 *q++ = *p;
613 }
614 }
615 *len = q - result;
616 return result;
617 }
619 int iolex( int expectToken )
620 {
621 int count = 0;
622 while( yystate.yyposn < yystate.yyend ) {
623 char *yystart = yytok.yytext = yystate.yyposn;
624 yytok.yylength = 1;
625 yytok.yyline = yystate.yylineno;
626 yytok.yycol = yystate.yyposn - yystate.yylineposn+1;
627 int ch = *yystate.yyposn++;
628 if( isdigit(ch) ) {
629 /* INTEGER */
630 if( ch == '0' ) {
631 if( *yystate.yyposn == 'x' ) {
632 while( yystate.yyposn < yystate.yyend && isxdigit(*++yystate.yyposn) ) ;
633 } else {
634 while( yystate.yyposn < yystate.yyend && *yystate.yyposn >= '0' && *yystate.yyposn <= '7' )
635 yystate.yyposn++;
636 }
637 } else {
638 while( yystate.yyposn < yystate.yyend && isdigit(*yystate.yyposn) )
639 yystate.yyposn++;
640 }
641 yytok.v.i = strtol( yystart, NULL, 0 );
642 YYRETURN(TOK_INTEGER);
643 } else if( isalpha(ch) || ch == '_' ) {
644 /* IDENTIFIER */
645 while( yystate.yyposn < yystate.yyend && (isalnum(*yystate.yyposn) || *yystate.yyposn == '_') )
646 yystate.yyposn++;
647 yytok.yylength = yystate.yyposn - yystart;
648 if( expectToken == TOK_IDENTIFIER ) {
649 YYRETURN(TOK_IDENTIFIER);
650 }
651 /* Otherwise check for keywords */
652 for( int i=FIRST_KEYWORD; i <= LAST_KEYWORD; i++ ) {
653 if( strlen(TOKEN_NAMES[i]) == yytok.yylength &&
654 strncasecmp(TOKEN_NAMES[i], yystart, yytok.yylength ) == 0 ) {
655 YYRETURN(i);
656 }
657 }
658 YYRETURN(TOK_IDENTIFIER);
659 } else if( isspace(ch) ) {
660 if( ch == '\n' ) {
661 yystate.yylineno++;
662 yystate.yylineposn = yystate.yyposn;
663 }
664 while( isspace(*yystate.yyposn) ) {
665 if( *yystate.yyposn == '\n' ) {
666 yystate.yylineno++;
667 yystate.yylineposn = yystate.yyposn+1;
668 }
669 yystate.yyposn++;
670 }
671 } else {
672 switch( ch ) {
673 case '(': YYRETURN(TOK_LPAREN);
674 case ')': YYRETURN(TOK_RPAREN);
675 case '[': YYRETURN(TOK_LSQUARE);
676 case ']': YYRETURN(TOK_RSQUARE);
677 case ',': YYRETURN(TOK_COMMA);
678 case ':': YYRETURN(TOK_COLON);
679 case ';': YYRETURN(TOK_SEMI);
680 case '=': YYRETURN(TOK_EQUALS);
681 case '/':
682 if( *yystate.yyposn == '/' ) { /* Line comment */
683 while( yystate.yyposn < yystate.yyend && *++yystate.yyposn != '\n' ) ;
684 } else if( *yystate.yyposn == '*' ) { /* C comment */
685 while( yystate.yyposn < yystate.yyend && (*++yystate.yyposn != '*' || *++yystate.yyposn != '/' ) ) {
686 if( *yystate.yyposn == '\n' ) {
687 yystate.yylineno++;
688 yystate.yylineposn = yystate.yyposn+1;
689 }
690 }
691 }
692 break;
693 case '\'': /* STRING */
694 while( *yystate.yyposn != '\'' ) {
695 if( *yystate.yyposn == '\n' ) {
696 fprintf( stderr, "Unexpected newline in string constant!\n" );
697 YYRETURN(TOK_ERROR);
698 } else if( yystate.yyposn >= yystate.yyend ) {
699 fprintf( stderr, "Unexpected EOF in string constant!\n" );
700 YYRETURN(TOK_ERROR);
701 } else if( *yystate.yyposn == '\\' && yystate.yyposn[1] == '\'' ) {
702 yystate.yyposn++;
703 }
704 yystate.yyposn++;
705 }
706 yystate.yyposn++;
707 yytok.v.s = iolex_getcstring(yystart+1, yystate.yyposn-1, &yytok.slen);
708 YYRETURN(TOK_STRING);
709 case '\"': /* STRING */
710 while( *yystate.yyposn != '\"' ) {
711 if( *yystate.yyposn == '\n' ) {
712 fprintf( stderr, "Unexpected newline in string constant!\n" );
713 YYRETURN(TOK_ERROR);
714 } else if( yystate.yyposn >= yystate.yyend ) {
715 fprintf( stderr, "Unexpected EOF in string constant!\n" );
716 YYRETURN(TOK_ERROR);
717 } else if( *yystate.yyposn == '\\' && yystate.yyposn[1] == '\"' ) {
718 yystate.yyposn++;
719 }
720 yystate.yyposn++;
721 }
722 yystate.yyposn++;
723 yytok.v.s = iolex_getcstring(yystart+1, yystate.yyposn-1, &yytok.slen);
724 YYRETURN(TOK_STRING);
725 case '}':
726 YYRETURN(TOK_RBRACE);
727 case '{': /* ACTION or LBRACE */
728 if( expectToken == TOK_LBRACE ) {
729 YYRETURN(TOK_LBRACE);
730 } else {
731 count++;
732 while( count > 0 && yystate.yyposn < yystate.yyend ) {
733 if( *yystate.yyposn == '{' )
734 count++;
735 if( *yystate.yyposn == '}' )
736 count--;
737 yystate.yyposn++;
738 }
739 YYRETURN(TOK_ACTION);
740 }
741 case '.':
742 if( *yystate.yyposn == '.' ) {
743 yystate.yyposn++;
744 YYRETURN(TOK_RANGE);
745 } else {
746 YYRETURN(TOK_PERIOD);
747 }
748 default:
749 fprintf( stderr, "Illegal character: '%c'\n", ch );
750 YYRETURN(TOK_ERROR);
751 }
752 }
754 }
755 return TOK_EOF;
756 }
.