157 lines
2.9 KiB
Plaintext
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 */
|