fxos/lib/load-target.l

157 lines
2.9 KiB
Plaintext

%{
#include <fxos/target.h>
#include <fxos/errors.h>
#include <fxos/util.h>
#include <string>
#include <cstring>
#include <cstdio>
#include <cstdarg>
/* Tokens */
#define NAME 0
#define ADDRESS 1
#define SIZE 2
#define PATH 3
/* Value for parser */
static union {
char *name;
uint32_t address;
uint32_t size;
char *path;
} yylval;
/* Current file name */
static std::string filename;
/* Error messages and exceptions */
__attribute__((noreturn))
static void err(char const *format, ...)
{
static char buf[256];
va_list args;
va_start(args, format);
vsnprintf(buf, 256, format, args);
va_end(args);
throw FxOS::SyntaxError(filename.c_str(), yylineno, buf);
}
%}
%option prefix="target"
%option noyywrap
%option nounput
name [a-zA-Z_][a-zA-Z0-9_]*
hexa [0-9a-fA-F]+
path [^: \t\n]+$
space [ \t]+
%%
^#[^\n]* ;
{space} ;
[\n] yylineno++;
{hexa} { sscanf(yytext, "%x", &yylval.address); return ADDRESS; }
"("{hexa}")" { sscanf(yytext, "(%x)", &yylval.size); return SIZE; }
{name} { yylval.name = strdup(yytext); return NAME; }
":" { return ':'; }
{path} { yylval.path = strdup(yytext); return PATH; }
. { err("lex error near '%s'", yytext); }
<<EOF>> { return -1; }
%%
namespace FxOS {
static int expect(std::vector<int> types)
{
std::array description {
"region name", "address", "size", "file path" };
int t = yylex();
for(int allowed: types) if(t == allowed) return t;
std::string errmsg = "expected";
for(int allowed: types)
{
if(allowed >= 0 && allowed < (int)description.size())
{
errmsg += " ";
errmsg += description[t];
errmsg += ",";
}
else if(allowed == -1)
{
errmsg += " end of file,";
}
else if(allowed == ':')
{
errmsg += " colon,";
}
}
err(errmsg.c_str());
}
static int expect(int type)
{
std::vector types { type };
return expect(types);
}
/* Load a target description into the target database. */
TargetDescription load_target(Buffer const &file, size_t offset, size_t line)
{
/* Build a target description without actually loading the files. */
TargetDescription descr;
YY_BUFFER_STATE buf = yy_scan_bytes(file.data.get() + offset,
file.size - offset);
yylineno = line;
filename = file.path;
while(1)
{
MemoryRegion reg;
/* One iteration per line */
int t = expect({ NAME, ADDRESS, -1 });
if(t == -1) break;
if(t == NAME)
{
reg = MemoryRegion(yylval.name);
free(yylval.name);
}
else if(t == ADDRESS)
{
uint32_t start = yylval.address;
expect(SIZE);
uint32_t size = yylval.size;
reg = MemoryRegion("(anonymous)", start, start + size,
true);
}
expect(':');
expect(PATH);
std::string path = yylval.path;
free(yylval.path);
TargetDescription::Binding b = std::make_pair(reg, path);
descr.bindings.push_back(b);
}
yy_delete_buffer(buf);
return descr;
}
} /* namespace FxOS */