%{ #include #include #include /* Values for tokens generated by the lexer */ static union { char *text; long long integer; } yylval; /* Token list */ #define NUMBER 0 #define SYMBOL 1 %} %option prefix="reg" %option noyywrap %option nounput decimal 0|[1-9][0-9]* octal 0[0-7]+ hexa 0x[0-9a-fA-F]+ number {decimal}|{octal}|{hexa} symbol [^0-9 \t\n][^\n]* space [ \t]+ %% ^#[^\n]* ; {space} ; [\n] yylineno++; {number} { yylval.integer = integer(yytext, NULL); return NUMBER; } {symbol} { yylval.text = strdup(yytext); return SYMBOL; } <> return -1; %% #include /* lex_reg(): Peripheral register table lexer and parser */ struct reg_address *lex_reg(void *data, size_t len, int *count) { /* Count number of register descriptions (upper bound) */ YY_BUFFER_STATE buf = yy_scan_bytes(data, len); yylineno = 1; int total = 0, t; while((t = yylex()) != -1) { total += (t == NUMBER); if(t == SYMBOL) free(yylval.text); } yy_delete_buffer(buf); /* Allocate a large enough register array */ struct reg_address *table = calloc(total, sizeof *table); if(!table) { errf(ERR_ERRNO, "cannot allocate memory for database"); return 0; } /* Lex all instructions and fill in the array */ buf = yy_scan_bytes(data, len); yylineno = 1; struct reg_address *reg = table - 1; int line = -1; while(1) { t = yylex(); if(t == NUMBER || t == -1) { /* Finalize current instruction */ if(reg >= table && !reg->name) err("%d: unnamed register", line); else reg++; } if(t == -1) break; if(t == NUMBER) { reg->address = yylval.integer; line = yylineno; } else if(t == SYMBOL && reg < table) { err("%d: expected register address", yylineno); free(yylval.text); } else if(t == SYMBOL && !reg->name) { reg->name = yylval.text; } else if(t == SYMBOL) { err("%d: excess names for 0x%08x\n", reg->address); free(yylval.text); } } yy_delete_buffer(buf); if(count) *count = reg - table; return table; }