1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/tools/mdparse.c Mon Mar 15 22:10:24 2010 +1000
1.7 + * genmmio I/O register definition parser.
1.9 + * Copyright (c) 2010 Nathan Keynes.
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.22 +#include <assert.h>
1.23 +#include <stdlib.h>
1.25 +#include <string.h>
1.26 +#include <unistd.h>
1.30 +#include <sys/stat.h>
1.31 +#include <glib/gmem.h>
1.33 +#include "genmach.h"
1.37 + * start: start register_block | ;
1.38 + * register_block: 'registers' IDENTIFIER 'at' INTEGER opt_paramlist '{' register_list '}';
1.39 + * opt_paramlist: '(' param_list ')' | '(' ')' | ;
1.40 + * param_list: param_list ',' param | param ;
1.41 + * param: access_param | fill_param | endian_param | mask_param ;
1.42 + * access_param: 'access' '=' 'any' // Behaves as if it were memory
1.43 + * | 'access' '=' 'nooffset' // Recognize any size access (zero-ext or trunc) as long as the address is exactly the same
1.44 + * | 'access' '=' 'exact' // Recognize only the exact access type at the exact address
1.46 + * fill_param: 'fill' '=' literal;
1.47 + * endian_param: 'endian' '=' 'little'
1.48 + * | 'endian' '=' 'big'
1.50 + * mask_param: 'mask' '=' literal;
1.52 + * register_list: register_list register_desc | ;
1.53 + * register_desc: INTEGER ':' mode_spec type_spec IDENTIFIER opt_paramlist [ '=' literal ] [ ACTION ]
1.54 + * mode_spec: 'const' | 'rw' | 'ro' | 'wo';
1.55 + * type_spec: 'i8' | 'i16' | 'i32' | 'i64' | 'f32' | 'f64' | 'string' | 'cstring';
1.56 + * literal: INTEGER | STRING | 'undefined' ;
1.58 + * C-style comments are recognized as such.
1.61 +#define TOK_IDENTIFIER 1
1.62 +#define TOK_INTEGER 2
1.63 +#define TOK_STRING 3
1.64 +#define TOK_ACTION 4
1.66 +#define TOK_ERROR 6
1.67 +#define TOK_LPAREN 7
1.68 +#define TOK_RPAREN 8
1.69 +#define TOK_LBRACE 9
1.70 +#define TOK_RBRACE 10
1.71 +#define TOK_COMMA 11
1.72 +#define TOK_COLON 12
1.73 +#define TOK_SEMI 13
1.74 +#define TOK_PERIOD 14
1.75 +#define TOK_RANGE 15
1.76 +#define TOK_LSQUARE 16
1.77 +#define TOK_RSQUARE 17
1.78 +#define TOK_EQUALS 18
1.79 +#define TOK_ACCESS 19
1.81 +#define TOK_ENDIAN 21
1.82 +#define TOK_FILL 22
1.83 +#define TOK_INCLUDE 23
1.84 +#define TOK_MASK 24
1.85 +#define TOK_REGISTERS 25
1.86 +#define TOK_SPACE 26
1.87 +#define TOK_STRIDE 27
1.88 +#define TOK_TEST 28
1.89 +#define TOK_TRACE 29
1.90 +#define TOK_UNDEFINED 30
1.93 +#define FIRST_KEYWORD TOK_ACCESS
1.94 +#define LAST_KEYWORD TOK_UNDEFINED
1.95 +static const char *TOKEN_NAMES[] = {"NULL", "IDENTIFIER", "INTEGER", "STRING", "ACTION", "EOF", "ERROR",
1.96 + "(", ")", "{", "}", ",", ":", ";", ".", "..", "[", "]", "=",
1.97 + "ACCESS", "AT", "ENDIAN", "FILL", "INCLUDE", "MASK", "REGISTERS", "SPACE", "STRIDE", "TEST", "TRACE", "UNDEFINED" };
1.98 +static const char *MODE_NAMES[] = {"const", "rw", "ro", "wo", "mirror"};
1.99 +static const char *TYPE_NAMES[] = {"i8", "i16", "i32", "i64", "f32", "f64", "string"};
1.100 +static int TYPE_SIZES[] = {1,2,4,8,4,8,0};
1.101 +static const char *ENDIAN_NAMES[] = {"default", "little", "big"};
1.102 +static const char *ACCESS_NAMES[] = {"default", "any", "nooffset", "exact"};
1.103 +static const char *TRACE_NAMES[] = {"default", "off", "on"};
1.105 +#define elementsof(x) (sizeof(x)/sizeof(x[0]))
1.107 +typedef struct token_data {
1.119 +static char *yybuffer;
1.120 +static char *yyposn, *yylineposn;
1.121 +static char *yyend;
1.122 +static int yyline;
1.123 +static struct token_data yytok;
1.125 +#define YYPARSE_ERROR( msg, ... ) \
1.127 + fprintf( stderr, "Parse error at %d:%d: " msg "\n", yytok.yyline, yytok.yycol, __VA_ARGS__ ); \
1.132 +{ int _tok = iolex(x); \
1.133 + if( _tok != (x) ) { \
1.134 + YYPARSE_ERROR( "Expected %s but got %s", TOKEN_NAMES[x], TOKEN_NAMES[_tok] ); \
1.138 +static int iolex( int expectToken );
1.139 +static int iolex_open( const char *filename );
1.140 +static void iolex_close();
1.142 +static inline char *yystrdup()
1.144 + char *str = g_malloc0(yytok.yylength+1);
1.145 + memcpy( str, yytok.yytext, yytok.yylength);
1.149 +static inline int yystrcasecmp(const char *cmp)
1.151 + int len = strlen(cmp);
1.152 + if( len != yytok.yylength ) {
1.153 + return yytok.yylength - len;
1.155 + return strncasecmp(yytok.yytext, cmp, yytok.yylength);
1.158 +static int yymatch( const char *arr[], unsigned numOptions )
1.160 + for( unsigned i=0; i<numOptions; i++ ) {
1.161 + if( yystrcasecmp( arr[i] ) == 0 ) {
1.168 +static gint register_block_sort_cb( gconstpointer a, gconstpointer b )
1.170 + struct regblock *blocka = (struct regblock *)a;
1.171 + struct regblock *blockb = (struct regblock *)b;
1.172 + return blocka->address - blockb->address;
1.175 +static int register_ptr_sort_cb( const void *a, const void *b )
1.177 + regdef_t *ptra = (regdef_t *)a;
1.178 + regdef_t *ptrb = (regdef_t *)b;
1.179 + if( (*ptra)->offset != (*ptrb)->offset )
1.180 + return (*ptra)->offset - (*ptrb)->offset;
1.181 + return (*ptra)->type - (*ptrb)->type;
1.184 +static void ioparse_apval(int tok, union apval *apv, unsigned *numBytes)
1.186 + if( tok == TOK_INTEGER ) {
1.187 + apv->i = yytok.v.i;
1.188 + if( *numBytes == 0 ) {
1.189 + YYPARSE_ERROR( "Expected string initializer but was an integer (0x%x)", yytok.v.i );
1.191 + } else if( tok = TOK_STRING ) {
1.192 + if( *numBytes == 0 ) {
1.193 + *numBytes = yytok.slen;
1.194 + apv->s = yytok.v.s;
1.196 + if( *numBytes != yytok.slen ) {
1.197 + YYPARSE_ERROR( "Expected %d byte initializer but was %d", *numBytes, yytok.slen );
1.199 + assert( *numBytes < sizeof(uint64_t) );
1.201 + /* FIXME: handle endian mismatches */
1.202 + memcpy( &apv->i, yytok.v.s, yytok.slen );
1.205 + YYPARSE_ERROR( "Expected literal (integer or string), but got %s", TOKEN_NAMES[tok] );
1.209 +static void ioparse_regflags( regflags_t flags, unsigned *numBytes )
1.212 + int tok = iolex(TOK_RPAREN);
1.215 + READ(TOK_EQUALS);
1.216 + tok = iolex(TOK_INTEGER);
1.217 + flags->fillSizeBytes = 4;
1.218 + ioparse_apval( tok, &flags->fillValue, &flags->fillSizeBytes );
1.221 + READ(TOK_EQUALS);
1.222 + READ(TOK_IDENTIFIER);
1.223 + flags->access = yymatch(ACCESS_NAMES,elementsof(ACCESS_NAMES));
1.224 + if( flags->access == -1 ) {
1.225 + YYPARSE_ERROR("Unknown access mode '%s'", yystrdup());
1.230 + READ(TOK_EQUALS);
1.231 + tok = iolex(TOK_INTEGER);
1.232 + ioparse_apval( tok, &flags->maskValue, numBytes );
1.234 + YYPARSE_ERROR("mask is not valid on a register block",0);
1.238 + READ(TOK_EQUALS);
1.239 + READ(TOK_IDENTIFIER);
1.240 + flags->endian = yymatch(ENDIAN_NAMES,elementsof(ENDIAN_NAMES));
1.241 + if( flags->endian == -1 ) {
1.242 + YYPARSE_ERROR("Unknown endianness '%s'", yystrdup());
1.246 + READ(TOK_EQUALS);
1.247 + READ(TOK_IDENTIFIER);
1.248 + flags->traceFlag = yymatch(TRACE_NAMES,elementsof(TRACE_NAMES));
1.249 + if( flags->traceFlag == -1 ) {
1.250 + YYPARSE_ERROR("Unknown trace flag '%s'", yystrdup());
1.254 + READ(TOK_EQUALS);
1.255 + READ(TOK_IDENTIFIER);
1.256 + flags->testFlag = yymatch(TRACE_NAMES,elementsof(TRACE_NAMES));
1.257 + if( flags->testFlag == -1 ) {
1.258 + YYPARSE_ERROR("Unknown test flag '%s'", yystrdup());
1.266 + YYPARSE_ERROR("Expected flag or ')' but was %s", TOKEN_NAMES[tok]);
1.271 +static void ioparse_regdef( struct regdef *reg )
1.273 + reg->offset = yytok.v.i;
1.274 + reg->numElements = 1;
1.275 + reg->numBytes = 0;
1.276 + reg->initValue.i = 0;
1.277 + reg->flags.maskValue.i = -1;
1.278 + unsigned rangeOffset = reg->offset;
1.280 + int tok = iolex(TOK_COLON);
1.281 + if( tok == TOK_RANGE ) {
1.282 + READ(TOK_INTEGER);
1.283 + rangeOffset = yytok.v.i;
1.284 + if( rangeOffset < reg->offset ) {
1.285 + YYPARSE_ERROR( "Range end (0x%x) must be greater than the range start (0x%x)", rangeOffset, reg->offset );
1.288 + } else if( tok != TOK_COLON ) {
1.289 + YYPARSE_ERROR( "Expected ':' but was %s\n", TOKEN_NAMES[tok] );
1.291 + READ(TOK_IDENTIFIER);
1.292 + reg->mode = yymatch(MODE_NAMES, elementsof(MODE_NAMES));
1.293 + if( reg->mode == -1 ) {
1.294 + YYPARSE_ERROR( "Unknown register mode '%s'", yystrdup() );
1.296 + if( reg->mode == REG_MIRROR ) {
1.297 + /* Mirror regions have a target range only */
1.298 + READ(TOK_INTEGER);
1.299 + reg->initValue.i = yytok.v.i;
1.300 + reg->type = REG_I8;
1.301 + tok = iolex(TOK_RANGE);
1.302 + if( tok == TOK_RANGE ) {
1.303 + READ(TOK_INTEGER);
1.304 + if( yytok.v.i < reg->initValue.i ) {
1.305 + YYPARSE_ERROR( "Invalid mirror target range 0x%x..0x%x", reg->initValue.i, yytok.v.i );
1.307 + reg->numBytes = yytok.v.i - reg->initValue.i + 1;
1.308 + tok = iolex(TOK_STRIDE);
1.310 + if( tok == TOK_STRIDE ) {
1.311 + READ(TOK_INTEGER);
1.312 + reg->stride = yytok.v.i;
1.313 + tok = iolex(TOK_ACTION);
1.315 + reg->stride = reg->numBytes;
1.318 + if( tok != TOK_SEMI ) {
1.319 + YYPARSE_ERROR( "Expected ; but gut %s", TOKEN_NAMES[tok] );
1.322 + if( reg->stride < reg->numBytes ) {
1.323 + YYPARSE_ERROR( "Invalid mirror stride: %x is less than block size %x\n", reg->stride, reg->numBytes );
1.326 + if( rangeOffset != reg->offset ) {
1.327 + reg->numElements *= ((rangeOffset - reg->offset) + reg->stride - 1) / reg->stride;
1.331 + READ(TOK_IDENTIFIER);
1.332 + reg->type = yymatch(TYPE_NAMES, elementsof(TYPE_NAMES));
1.333 + if( reg->type == -1 ) {
1.334 + YYPARSE_ERROR( "Unknown register type '%s'", yystrdup() );
1.336 + reg->numBytes = TYPE_SIZES[reg->type];
1.337 + tok = iolex(TOK_IDENTIFIER);
1.338 + if( tok == TOK_IDENTIFIER ) {
1.339 + reg->name = yystrdup();
1.340 + tok = iolex(TOK_ACTION);
1.342 + if( tok == TOK_STRING ) {
1.343 + reg->description = yytok.v.s;
1.344 + tok = iolex(TOK_ACTION);
1.346 + if( tok == TOK_LPAREN ) {
1.347 + ioparse_regflags(®->flags, ®->numBytes);
1.348 + tok = iolex(TOK_ACTION);
1.350 + if( tok == TOK_EQUALS ) {
1.351 + tok = iolex(TOK_INTEGER);
1.352 + if( tok == TOK_UNDEFINED ) {
1.353 + reg->initValue.i = 0xDEADBEEFDEADBEEF;
1.354 + reg->initUndefined = TRUE;
1.356 + ioparse_apval(tok, ®->initValue, ®->numBytes);
1.358 + tok = iolex(TOK_ACTION);
1.359 + } else if( reg->type == REG_STRING ) {
1.360 + YYPARSE_ERROR( "String declarations must have an initializer (ie = 'abcd')",0 );
1.362 + if( tok == TOK_ACTION ) {
1.363 + // reg->action = yystrdup();
1.364 + } else if( tok != TOK_SEMI ) {
1.365 + YYPARSE_ERROR( "Expected ; or {, but got %s", TOKEN_NAMES[tok] );
1.368 + if( rangeOffset != reg->offset ) {
1.369 + reg->numElements *= ((rangeOffset - reg->offset) + reg->numBytes - 1) / reg->numBytes;
1.375 +static struct regblock *ioparse_regblock( )
1.377 + unsigned regsAllocSize = 128;
1.378 + struct regblock *block = g_malloc0(sizeof(struct regblock) + sizeof(regdef_t)*regsAllocSize);
1.379 + block->numRegs = 0;
1.381 + READ(TOK_IDENTIFIER);
1.382 + block->name = yystrdup();
1.383 + int tok = iolex(TOK_AT);
1.384 + if( tok == TOK_STRING ) {
1.385 + block->description = yytok.v.s;
1.386 + tok = iolex(TOK_AT);
1.388 + if( tok != TOK_AT ) {
1.389 + YYPARSE_ERROR("Expected AT but got %s\n", TOKEN_NAMES[tok] );
1.391 + READ(TOK_INTEGER);
1.392 + block->address = yytok.v.i;
1.394 + tok = iolex(TOK_LBRACE);
1.395 + if( tok == TOK_LPAREN) {
1.396 + ioparse_regflags(&block->flags, NULL);
1.397 + READ(TOK_LBRACE);
1.398 + } else if( tok != TOK_LBRACE ) {
1.399 + YYPARSE_ERROR("Expected { but got %s\n", TOKEN_NAMES[tok] );
1.402 + tok = iolex(TOK_INTEGER);
1.403 + while( tok != TOK_RBRACE ) {
1.404 + if( tok != TOK_INTEGER ) {
1.405 + YYPARSE_ERROR("Expected INTEGER or } but got %s\n", TOKEN_NAMES[tok]);
1.407 + struct regdef *regdef = g_malloc0(sizeof(struct regdef));
1.408 + if( block->numRegs >= regsAllocSize ) {
1.409 + regsAllocSize *= 2;
1.410 + block = g_realloc(block, sizeof(struct regblock) + sizeof(regdef_t)*regsAllocSize);
1.412 + block->regs[block->numRegs++] = regdef;
1.413 + ioparse_regdef(regdef);
1.415 + tok = iolex(TOK_INTEGER);
1.418 + qsort( &block->regs[0], block->numRegs, sizeof(block->regs[0]), register_ptr_sort_cb );
1.423 +GList *ioparse( const char *filename, GList *list )
1.425 + GList *blocks = list;
1.428 + if( iolex_open(filename) != 0 )
1.433 + tok = iolex(TOK_REGISTERS);
1.434 + if( tok == TOK_EOF ) {
1.436 + } else if( tok == TOK_INCLUDE) {
1.437 + READ(TOK_STRING);
1.439 + } else if( tok == TOK_SPACE ) {
1.440 + } else if( tok == TOK_REGISTERS ) {
1.441 + struct regblock *block = ioparse_regblock(block);
1.443 + blocks = g_list_insert_sorted(blocks, block, register_block_sort_cb);
1.445 + YYPARSE_ERROR("Expected REGISTERS but got %s\n", TOKEN_NAMES[tok] );
1.447 + } while( tok != TOK_EOF );
1.450 + if( count == 0 ) {
1.451 + fprintf( stderr, "Warning: input file '%s' did not contain any register definitions\n" );
1.457 +/**************************** Lexical analyser ***************************/
1.459 +static int iolex_open( const char *filename )
1.462 + int fd = open( filename, O_RDONLY );
1.464 + fprintf( stderr, "Error opening file '%s': %s\n", filename, strerror(errno) );
1.468 + if( fstat( fd, &st ) != 0 ) {
1.469 + fprintf( stderr, "Error statting file '%s': %s\n", filename, strerror(errno) );
1.474 + char *data = g_malloc( st.st_size + 1 );
1.475 + if( read(fd, data, st.st_size) != st.st_size ) {
1.476 + fprintf( stderr, "Error reading file '%s': %s\n", filename, strerror(errno) );
1.481 + data[st.st_size] = 0;
1.483 + yybuffer = yyposn = data;
1.484 + yyend = data + st.st_size;
1.486 + yylineposn = yyposn;
1.490 +static void iolex_close()
1.492 + g_free(yybuffer);
1.493 + yybuffer = yyend = NULL;
1.496 +#define YYRETURN(x) do{ \
1.497 + yytok.yylength = yyposn - yystart; \
1.501 +static int iolex_readhex(char *p, int digits)
1.504 + for( int i=0; i < digits; i++ ) {
1.506 + if( isdigit(p[i]) ) {
1.507 + result += p[i]-'0';
1.508 + } else if( p[i] >= 'a' && p[i] <= 'f' ) {
1.509 + result += p[i]-'a'+10;
1.510 + } else if( p[i] >= 'A' && p[i] <= 'F' ) {
1.511 + result += p[i]-'A'+10;
1.513 + return (result >> 4);
1.520 +static int iolex_readoctal(char *p, int digits)
1.523 + for( int i=0; i < digits; i++ ) {
1.525 + if( p[i] >= '0' && p[i] <= '7' ) {
1.526 + result += p[i]-'0';
1.528 + return (result >> 4);
1.535 + * Copy and interpret the string segment as a C string, replacing escape
1.536 + * expressions with the corresponding value.
1.538 +static char *iolex_getcstring( char *start, char *end, int *len )
1.540 + char *result = g_malloc0(end-start+1); /* Allocate enough memory for the string as-is */
1.541 + char *q = result;
1.543 + for( char *p = start; p != end; p++ ) {
1.544 + if( *p == '\\' ) {
1.545 + if( ++p == end ) {
1.549 + if( p[0] >= '0' && p[0] <= '3' && p+3 <= end &&
1.550 + p[1] >= '0' && p[1] <= '7' &&
1.551 + p[2] >= '0' && p[2] <= '7' ) {
1.552 + *q++ = (char)iolex_readoctal(p,3);
1.565 + case 'x': /* hex */
1.566 + if( p + 3 > end || !isxdigit(p[1]) || !isxdigit(p[2]) ) {
1.570 + *q++ = (char)iolex_readhex(p+1, 2);
1.583 + *len = q - result;
1.587 +int iolex( int expectToken )
1.590 + while( yyposn < yyend ) {
1.591 + char *yystart = yytok.yytext = yyposn;
1.592 + yytok.yylength = 1;
1.593 + yytok.yyline = yyline;
1.594 + yytok.yycol = yyposn - yylineposn+1;
1.595 + int ch = *yyposn++;
1.596 + if( isdigit(ch) ) {
1.598 + if( ch == '0' ) {
1.599 + if( *yyposn == 'x' ) {
1.600 + while( yyposn < yyend && isxdigit(*++yyposn) ) ;
1.602 + while( yyposn < yyend && *yyposn >= '0' && *yyposn <= '7' )
1.606 + while( yyposn < yyend && isdigit(*yyposn) )
1.609 + yytok.v.i = strtol( yystart, NULL, 0 );
1.610 + YYRETURN(TOK_INTEGER);
1.611 + } else if( isalpha(ch) || ch == '_' ) {
1.613 + while( yyposn < yyend && (isalnum(*yyposn) || *yyposn == '_') )
1.615 + yytok.yylength = yyposn - yystart;
1.616 + if( expectToken == TOK_IDENTIFIER ) {
1.617 + YYRETURN(TOK_IDENTIFIER);
1.619 + /* Otherwise check for keywords */
1.620 + for( int i=FIRST_KEYWORD; i <= LAST_KEYWORD; i++ ) {
1.621 + if( strlen(TOKEN_NAMES[i]) == yytok.yylength &&
1.622 + strncasecmp(TOKEN_NAMES[i], yystart, yytok.yylength ) == 0 ) {
1.626 + YYRETURN(TOK_IDENTIFIER);
1.627 + } else if( isspace(ch) ) {
1.628 + if( ch == '\n' ) {
1.630 + yylineposn = yyposn;
1.632 + while( isspace(*yyposn) ) {
1.633 + if( *yyposn == '\n' ) {
1.635 + yylineposn = yyposn+1;
1.641 + case '(': YYRETURN(TOK_LPAREN);
1.642 + case ')': YYRETURN(TOK_RPAREN);
1.643 + case '[': YYRETURN(TOK_LSQUARE);
1.644 + case ']': YYRETURN(TOK_RSQUARE);
1.645 + case ',': YYRETURN(TOK_COMMA);
1.646 + case ':': YYRETURN(TOK_COLON);
1.647 + case ';': YYRETURN(TOK_SEMI);
1.648 + case '=': YYRETURN(TOK_EQUALS);
1.650 + if( *yyposn == '/' ) { /* Line comment */
1.651 + while( yyposn < yyend && *++yyposn != '\n' ) ;
1.652 + } else if( *yyposn == '*' ) { /* C comment */
1.653 + while( yyposn < yyend && (*++yyposn != '*' || *++yyposn != '/' ) ) {
1.654 + if( *yyposn == '\n' ) {
1.656 + yylineposn = yyposn+1;
1.661 + case '\'': /* STRING */
1.662 + while( *yyposn != '\'' ) {
1.663 + if( *yyposn == '\n' ) {
1.664 + fprintf( stderr, "Unexpected newline in string constant!\n" );
1.665 + YYRETURN(TOK_ERROR);
1.666 + } else if( yyposn >= yyend ) {
1.667 + fprintf( stderr, "Unexpected EOF in string constant!\n" );
1.668 + YYRETURN(TOK_ERROR);
1.669 + } else if( *yyposn == '\\' && yyposn[1] == '\'' ) {
1.675 + yytok.v.s = iolex_getcstring(yystart+1, yyposn-1, &yytok.slen);
1.676 + YYRETURN(TOK_STRING);
1.677 + case '\"': /* STRING */
1.678 + while( *yyposn != '\"' ) {
1.679 + if( *yyposn == '\n' ) {
1.680 + fprintf( stderr, "Unexpected newline in string constant!\n" );
1.681 + YYRETURN(TOK_ERROR);
1.682 + } else if( yyposn >= yyend ) {
1.683 + fprintf( stderr, "Unexpected EOF in string constant!\n" );
1.684 + YYRETURN(TOK_ERROR);
1.685 + } else if( *yyposn == '\\' && yyposn[1] == '\"' ) {
1.691 + yytok.v.s = iolex_getcstring(yystart+1, yyposn-1, &yytok.slen);
1.692 + YYRETURN(TOK_STRING);
1.694 + YYRETURN(TOK_RBRACE);
1.695 + case '{': /* ACTION or LBRACE */
1.696 + if( expectToken == TOK_LBRACE ) {
1.697 + YYRETURN(TOK_LBRACE);
1.700 + while( count > 0 && yyposn < yyend ) {
1.701 + if( *yyposn == '{' )
1.703 + if( *yyposn == '}' )
1.707 + YYRETURN(TOK_ACTION);
1.710 + if( *yyposn == '.' ) {
1.712 + YYRETURN(TOK_RANGE);
1.714 + YYRETURN(TOK_PERIOD);
1.717 + fprintf( stderr, "Illegal character: '%c'\n", ch );
1.718 + YYRETURN(TOK_ERROR);