| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| /* |
| * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. |
| */ |
| |
| %option noyywrap nounput noinput never-interactive |
| |
| %x BYTESTRING |
| %x PROPNODENAME |
| %s V1 |
| |
| PROPNODECHAR [a-zA-Z0-9,._+*#?@-] |
| PATHCHAR ({PROPNODECHAR}|[/]) |
| LABEL [a-zA-Z_][a-zA-Z0-9_]* |
| STRING \"([^\\"]|\\.)*\" |
| CHAR_LITERAL '([^']|\\')*' |
| WS [[:space:]] |
| COMMENT "/*"([^*]|\*+[^*/])*\*+"/" |
| LINECOMMENT "//".*\n |
| |
| %{ |
| #include "dtc.h" |
| #include "srcpos.h" |
| #include "dtc-parser.h" |
| |
| extern bool treesource_error; |
| |
| /* CAUTION: this will stop working if we ever use yyless() or yyunput() */ |
| #define YY_USER_ACTION \ |
| { \ |
| srcpos_update(&yylloc, yytext, yyleng); \ |
| } |
| |
| /*#define LEXDEBUG 1*/ |
| |
| #ifdef LEXDEBUG |
| #define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) |
| #else |
| #define DPRINT(fmt, ...) do { } while (0) |
| #endif |
| |
| static int dts_version = 1; |
| |
| #define BEGIN_DEFAULT() DPRINT("<V1>\n"); \ |
| BEGIN(V1); \ |
| |
| static void push_input_file(const char *filename); |
| static bool pop_input_file(void); |
| static void PRINTF(1, 2) lexical_error(const char *fmt, ...); |
| |
| %} |
| |
| %% |
| <*>"/include/"{WS}*{STRING} { |
| char *name = strchr(yytext, '\"') + 1; |
| yytext[yyleng-1] = '\0'; |
| push_input_file(name); |
| } |
| |
| <*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* { |
| char *line, *fnstart, *fnend; |
| struct data fn; |
| /* skip text before line # */ |
| line = yytext; |
| while (!isdigit((unsigned char)*line)) |
| line++; |
| |
| /* regexp ensures that first and list " |
| * in the whole yytext are those at |
| * beginning and end of the filename string */ |
| fnstart = memchr(yytext, '"', yyleng); |
| for (fnend = yytext + yyleng - 1; |
| *fnend != '"'; fnend--) |
| ; |
| assert(fnstart && fnend && (fnend > fnstart)); |
| |
| fn = data_copy_escape_string(fnstart + 1, |
| fnend - fnstart - 1); |
| |
| /* Don't allow nuls in filenames */ |
| if (memchr(fn.val, '\0', fn.len - 1)) |
| lexical_error("nul in line number directive"); |
| |
| /* -1 since #line is the number of the next line */ |
| srcpos_set_line(xstrdup(fn.val), atoi(line) - 1); |
| data_free(fn); |
| } |
| |
| <*><<EOF>> { |
| if (!pop_input_file()) { |
| yyterminate(); |
| } |
| } |
| |
| <*>{STRING} { |
| DPRINT("String: %s\n", yytext); |
| yylval.data = data_copy_escape_string(yytext+1, |
| yyleng-2); |
| return DT_STRING; |
| } |
| |
| <*>"/dts-v1/" { |
| DPRINT("Keyword: /dts-v1/\n"); |
| dts_version = 1; |
| BEGIN_DEFAULT(); |
| return DT_V1; |
| } |
| |
| <*>"/plugin/" { |
| DPRINT("Keyword: /plugin/\n"); |
| return DT_PLUGIN; |
| } |
| |
| <*>"/memreserve/" { |
| DPRINT("Keyword: /memreserve/\n"); |
| BEGIN_DEFAULT(); |
| return DT_MEMRESERVE; |
| } |
| |
| <*>"/bits/" { |
| DPRINT("Keyword: /bits/\n"); |
| BEGIN_DEFAULT(); |
| return DT_BITS; |
| } |
| |
| <*>"/delete-property/" { |
| DPRINT("Keyword: /delete-property/\n"); |
| DPRINT("<PROPNODENAME>\n"); |
| BEGIN(PROPNODENAME); |
| return DT_DEL_PROP; |
| } |
| |
| <*>"/delete-node/" { |
| DPRINT("Keyword: /delete-node/\n"); |
| DPRINT("<PROPNODENAME>\n"); |
| BEGIN(PROPNODENAME); |
| return DT_DEL_NODE; |
| } |
| |
| <*>"/omit-if-no-ref/" { |
| DPRINT("Keyword: /omit-if-no-ref/\n"); |
| DPRINT("<PROPNODENAME>\n"); |
| BEGIN(PROPNODENAME); |
| return DT_OMIT_NO_REF; |
| } |
| |
| <*>{LABEL}: { |
| DPRINT("Label: %s\n", yytext); |
| yylval.labelref = xstrdup(yytext); |
| yylval.labelref[yyleng-1] = '\0'; |
| return DT_LABEL; |
| } |
| |
| <V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? { |
| char *e; |
| DPRINT("Integer Literal: '%s'\n", yytext); |
| |
| errno = 0; |
| yylval.integer = strtoull(yytext, &e, 0); |
| |
| if (*e && e[strspn(e, "UL")]) { |
| lexical_error("Bad integer literal '%s'", |
| yytext); |
| } |
| |
| if (errno == ERANGE) |
| lexical_error("Integer literal '%s' out of range", |
| yytext); |
| else |
| /* ERANGE is the only strtoull error triggerable |
| * by strings matching the pattern */ |
| assert(errno == 0); |
| return DT_LITERAL; |
| } |
| |
| <*>{CHAR_LITERAL} { |
| struct data d; |
| DPRINT("Character literal: %s\n", yytext); |
| |
| d = data_copy_escape_string(yytext+1, yyleng-2); |
| if (d.len == 1) { |
| lexical_error("Empty character literal"); |
| yylval.integer = 0; |
| } else { |
| yylval.integer = (unsigned char)d.val[0]; |
| |
| if (d.len > 2) |
| lexical_error("Character literal has %d" |
| " characters instead of 1", |
| d.len - 1); |
| } |
| |
| data_free(d); |
| return DT_CHAR_LITERAL; |
| } |
| |
| <*>\&{LABEL} { /* label reference */ |
| DPRINT("Ref: %s\n", yytext+1); |
| yylval.labelref = xstrdup(yytext+1); |
| return DT_LABEL_REF; |
| } |
| |
| <*>"&{"{PATHCHAR}*\} { /* new-style path reference */ |
| yytext[yyleng-1] = '\0'; |
| DPRINT("Ref: %s\n", yytext+2); |
| yylval.labelref = xstrdup(yytext+2); |
| return DT_PATH_REF; |
| } |
| |
| <BYTESTRING>[0-9a-fA-F]{2} { |
| yylval.byte = strtol(yytext, NULL, 16); |
| DPRINT("Byte: %02x\n", (int)yylval.byte); |
| return DT_BYTE; |
| } |
| |
| <BYTESTRING>"]" { |
| DPRINT("/BYTESTRING\n"); |
| BEGIN_DEFAULT(); |
| return ']'; |
| } |
| |
| <PROPNODENAME>\\?{PROPNODECHAR}+ { |
| DPRINT("PropNodeName: %s\n", yytext); |
| yylval.propnodename = xstrdup((yytext[0] == '\\') ? |
| yytext + 1 : yytext); |
| BEGIN_DEFAULT(); |
| return DT_PROPNODENAME; |
| } |
| |
| "/incbin/" { |
| DPRINT("Binary Include\n"); |
| return DT_INCBIN; |
| } |
| |
| <*>{WS}+ /* eat whitespace */ |
| <*>{COMMENT}+ /* eat C-style comments */ |
| <*>{LINECOMMENT}+ /* eat C++-style comments */ |
| |
| <*>"<<" { return DT_LSHIFT; }; |
| <*>">>" { return DT_RSHIFT; }; |
| <*>"<=" { return DT_LE; }; |
| <*>">=" { return DT_GE; }; |
| <*>"==" { return DT_EQ; }; |
| <*>"!=" { return DT_NE; }; |
| <*>"&&" { return DT_AND; }; |
| <*>"||" { return DT_OR; }; |
| |
| <*>. { |
| DPRINT("Char: %c (\\x%02x)\n", yytext[0], |
| (unsigned)yytext[0]); |
| if (yytext[0] == '[') { |
| DPRINT("<BYTESTRING>\n"); |
| BEGIN(BYTESTRING); |
| } |
| if ((yytext[0] == '{') |
| || (yytext[0] == ';')) { |
| DPRINT("<PROPNODENAME>\n"); |
| BEGIN(PROPNODENAME); |
| } |
| return yytext[0]; |
| } |
| |
| %% |
| |
| static void push_input_file(const char *filename) |
| { |
| assert(filename); |
| |
| srcfile_push(filename); |
| |
| yyin = current_srcfile->f; |
| |
| yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE)); |
| } |
| |
| |
| static bool pop_input_file(void) |
| { |
| if (srcfile_pop() == 0) |
| return false; |
| |
| yypop_buffer_state(); |
| yyin = current_srcfile->f; |
| |
| return true; |
| } |
| |
| static void lexical_error(const char *fmt, ...) |
| { |
| va_list ap; |
| |
| va_start(ap, fmt); |
| srcpos_verror(&yylloc, "Lexical error", fmt, ap); |
| va_end(ap); |
| |
| treesource_error = true; |
| } |