%{ #include #include #include #include #include #include #include /* 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); } <> { 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 */