fxos/lib/load-header.l

133 lines
2.3 KiB
Plaintext

%{
#include <fxos/load.h>
#include <fxos/errors.h>
#include <fxos/util.h>
#include <string>
#include <cstring>
#include <cstdio>
#include <cstdarg>
/* Text value for parser */
static char *yylval;
/* Tokens */
#define LITERAL 1
#define COLON 2
#define HEADER_END 3
/* Current file name and number of characters lexed */
static std::string filename;
static int lexed;
/* Automatically count lexed characters */
#define YY_USER_ACTION lexed += yyleng;
/* Error messages and exceptions */
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="header"
%option noyywrap
%option nounput
literal [a-zA-Z0-9_-]+
space [ \t]+
%%
^#[^\n]* ;
{space} ;
[\n] yylineno++;
{literal} { yylval = strdup(yytext); return LITERAL; }
^[ ]*-{3,}[ ]*$ { return HEADER_END; }
^. { err("invalid header line"); }
":" { return COLON; }
. { err("lex error near '%s'", yytext); }
<<EOF>> { err("EOF reached before header ends"); }
%%
namespace FxOS {
/* Load the header of a data file. */
Header load_header(File &file, size_t &offset_ref, int &line_ref)
{
/* Build a map of properties */
FxOS::Header header;
YY_BUFFER_STATE buf = yy_scan_bytes(file.data(), file.size());
filename = file.path();
yylineno = 1;
lexed = 0;
/* Current line */
int line = -1;
/* Property name and value */
char const *name = nullptr;
char const *value = nullptr;
while(1)
{
int t = yylex();
if(line >= 0 && (yylineno != line || t == HEADER_END))
{
/* Finalize current line */
if(!name || !value) {
yylineno = line;
err("incomplete header line");
}
/* Fill in the map */
header[name] = value;
name = nullptr;
value = nullptr;
}
if(t == HEADER_END) break;
line = yylineno;
if(t == COLON)
{
if(!name || value) err("misplaced colon in header");
}
else if(!name)
{
name = yylval;
}
else if(!value)
{
value = yylval;
}
else
{
err("unexpected stuff after header line");
}
}
offset_ref = lexed;
line_ref = yylineno;
yy_delete_buffer(buf);
return header;
}
} /* namespace FxOS */