forked from Lephenixnoir/fxos
133 lines
2.3 KiB
Plaintext
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 */
|