fxsdk/fxos/lexer-sys.l
Lephe 25db504c22 fxos: bring disassembling to a new level
Almost-complete implementation of fxos, the disassembler in particular
is now able to detect syscalls and register addresses on the fly, plus
support for SH4-only instructions.
2019-05-03 11:19:36 +02:00

123 lines
2.1 KiB
Text

%{
#include <fxos.h>
#include <errors.h>
#include <util.h>
/* 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; }
<<EOF>> return -1;
%%
#include <stdio.h>
/* 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;
}