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