%{ #include #include #include /* Values for tokens generated by the lexer */ static union { char *text; long long integer; } yylval; /* Token list */ #define NUMBER 0 #define TEXT 1 %} %option prefix="sys" %option noyywrap %option nounput decimal 0|[1-9][0-9]* octal 0[0-7]+ hexa 0x[0-9a-fA-F]+ number {decimal}|{octal}|{hexa} space [ \t]+ %% ^#[^\n]* ; {space} ; [\n] yylineno++; {number} { yylval.integer = integer(yytext, NULL); return NUMBER; } [^ \t\n0-9].* { yylval.text = strdup(yytext); return TEXT; } <> return -1; %% #include /* lex_sys(): Syscall table lexer and parser */ struct sys_call *lex_sys(void *data, size_t len, int *count) { /* Count the number of syscalls */ YY_BUFFER_STATE buf = yy_scan_bytes(data, len); yylineno = 1; int total = 0, t; while((t = yylex()) != -1) { total += (t == NUMBER); if(t == TEXT) free(yylval.text); } yy_delete_buffer(buf); /* Allocate a large enough syscall array */ struct sys_call *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 sys_call *call = table - 1; int line = -1; int named = 1; while(1) { t = yylex(); if(t == NUMBER || t == -1) { /* Finalize current instruction */ if(!named) err("%d: unnamed syscall", line); else call++; } if(t == -1) break; if(t == NUMBER) { call->number = yylval.integer; line = yylineno; named = 0; } else if(t == TEXT && call < table) { err("%d: expected syscall id", yylineno); free(yylval.text); } else if(t == TEXT && named == 0) { call->name = yylval.text; named = 1; } else if(t == TEXT && named == 1) { call->descr = yylval.text; named = 2; } else if(t == TEXT) { err("%d: excess qualifiers for syscall 0x%03x", line, call->number); free(yylval.text); } } yy_delete_buffer(buf); if(count) *count = call - table; return table; }