blob: 384f848c5e036c0fffae0ba69cc1879988712d19 [file] [log] [blame]
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%option noyywrap nounput yylineno
%x INCLUDE
%x CELLDATA
%x BYTESTRING
%x MEMRESERVE
PROPCHAR [a-zA-Z0-9,._+*#?-]
UNITCHAR [0-9a-f,]
WS [[:space:]]
REFCHAR ({PROPCHAR}|{UNITCHAR}|[/@])
%{
#include "dtc.h"
#include "srcpos.h"
#include "dtc-parser.tab.h"
/*#define LEXDEBUG 1*/
#ifdef LEXDEBUG
#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
#else
#define DPRINT(fmt, ...) do { } while (0)
#endif
%}
%%
"/include/" BEGIN(INCLUDE);
<INCLUDE>\"[^"\n]*\" {
yytext[strlen(yytext) - 1] = 0;
if (!push_input_file(yytext + 1)) {
/* Some unrecoverable error.*/
exit(1);
}
BEGIN(INITIAL);
}
<<EOF>> {
if (!pop_input_file()) {
yyterminate();
}
}
\"[^"]*\" {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("String: %s\n", yytext);
yylval.data = data_copy_escape_string(yytext+1,
yyleng-2);
yylloc.first_line = yylineno;
return DT_STRING;
}
"/memreserve/" {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("Keyword: /memreserve/\n");
BEGIN(MEMRESERVE);
return DT_MEMRESERVE;
}
<MEMRESERVE>[0-9a-fA-F]+ {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
if (yyleng > 2*sizeof(yylval.addr)) {
fprintf(stderr, "Address value %s too large\n",
yytext);
}
yylval.addr = (u64) strtoull(yytext, NULL, 16);
DPRINT("Addr: %llx\n",
(unsigned long long)yylval.addr);
return DT_ADDR;
}
<MEMRESERVE>";" {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("/MEMRESERVE\n");
BEGIN(INITIAL);
return ';';
}
<*>[a-zA-Z_][a-zA-Z0-9_]*: {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("Label: %s\n", yytext);
yylval.str = strdup(yytext);
yylval.str[yyleng-1] = '\0';
return DT_LABEL;
}
<CELLDATA>[bodh]# {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
if (*yytext == 'b')
yylval.cbase = 2;
else if (*yytext == 'o')
yylval.cbase = 8;
else if (*yytext == 'd')
yylval.cbase = 10;
else
yylval.cbase = 16;
DPRINT("Base: %d\n", yylval.cbase);
return DT_BASE;
}
<CELLDATA>[0-9a-fA-F]+ {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
yylval.str = strdup(yytext);
DPRINT("Cell: '%s'\n", yylval.str);
return DT_CELL;
}
<CELLDATA>">" {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("/CELLDATA\n");
BEGIN(INITIAL);
return '>';
}
<CELLDATA>\&{REFCHAR}* {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1);
yylval.str = strdup(yytext+1);
return DT_REF;
}
<BYTESTRING>[0-9a-fA-F]{2} {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
return DT_BYTE;
}
<BYTESTRING>"]" {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("/BYTESTRING\n");
BEGIN(INITIAL);
return ']';
}
, { /* Technically this is a valid property name,
but we'd rather use it as punctuation, so detect it
here in preference */
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("Char (propname like): %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
return yytext[0];
}
{PROPCHAR}+ {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("PropName: %s\n", yytext);
yylval.str = strdup(yytext);
return DT_PROPNAME;
}
{PROPCHAR}+(@{UNITCHAR}+)? {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("NodeName: %s\n", yytext);
yylval.str = strdup(yytext);
return DT_NODENAME;
}
<*>{WS}+ /* eat whitespace */
<*>"/*"([^*]|\*+[^*/])*\*+"/" {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
DPRINT("Comment: %s\n", yytext);
/* eat comments */
}
<*>"//".*\n /* eat line comments */
<*>. {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno;
switch (yytext[0]) {
case '<':
DPRINT("CELLDATA\n");
BEGIN(CELLDATA);
break;
case '[':
DPRINT("BYTESTRING\n");
BEGIN(BYTESTRING);
break;
default:
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
break;
}
return yytext[0];
}
%%
/*
* Stack of nested include file contexts.
*/
struct incl_file {
int filenum;
FILE *file;
YY_BUFFER_STATE yy_prev_buf;
int yy_prev_lineno;
struct incl_file *prev;
};
struct incl_file *incl_file_stack;
/*
* Detect infinite include recursion.
*/
#define MAX_INCLUDE_DEPTH (100)
static int incl_depth = 0;
int push_input_file(const char *filename)
{
FILE *f;
struct incl_file *incl_file;
if (!filename) {
yyerror("No include file name given.");
return 0;
}
if (incl_depth++ >= MAX_INCLUDE_DEPTH) {
yyerror("Includes nested too deeply");
return 0;
}
f = dtc_open_file(filename);
incl_file = malloc(sizeof(struct incl_file));
if (!incl_file) {
yyerror("Can not allocate include file space.");
return 0;
}
/*
* Save current context.
*/
incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
incl_file->yy_prev_lineno = yylineno;
incl_file->filenum = srcpos_filenum;
incl_file->file = yyin;
incl_file->prev = incl_file_stack;
incl_file_stack = incl_file;
/*
* Establish new context.
*/
srcpos_filenum = lookup_file_name(filename, 0);
yylineno = 1;
yyin = f;
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
return 1;
}
int pop_input_file(void)
{
struct incl_file *incl_file;
if (incl_file_stack == 0)
return 0;
fclose(yyin);
/*
* Pop.
*/
--incl_depth;
incl_file = incl_file_stack;
incl_file_stack = incl_file->prev;
/*
* Recover old context.
*/
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(incl_file->yy_prev_buf);
yylineno = incl_file->yy_prev_lineno;
srcpos_filenum = incl_file->filenum;
yyin = incl_file->file;
/*
* Free old state.
*/
free(incl_file);
if (YY_CURRENT_BUFFER == 0)
return 0;
return 1;
}