1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-or-later */ 2*4882a593Smuzhiyun /* 3*4882a593Smuzhiyun * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. 4*4882a593Smuzhiyun */ 5*4882a593Smuzhiyun 6*4882a593Smuzhiyun %option noyywrap nounput noinput never-interactive 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun %x BYTESTRING 9*4882a593Smuzhiyun %x PROPNODENAME 10*4882a593Smuzhiyun %s V1 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun PROPNODECHAR [a-zA-Z0-9,._+*#?@-] 13*4882a593Smuzhiyun PATHCHAR ({PROPNODECHAR}|[/]) 14*4882a593Smuzhiyun LABEL [a-zA-Z_][a-zA-Z0-9_]* 15*4882a593Smuzhiyun STRING \"([^\\"]|\\.)*\" 16*4882a593Smuzhiyun CHAR_LITERAL '([^']|\\')*' 17*4882a593Smuzhiyun WS [[:space:]] 18*4882a593Smuzhiyun COMMENT "/*"([^*]|\*+[^*/])*\*+"/" 19*4882a593Smuzhiyun LINECOMMENT "//".*\n 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun %{ 22*4882a593Smuzhiyun #include "dtc.h" 23*4882a593Smuzhiyun #include "srcpos.h" 24*4882a593Smuzhiyun #include "dtc-parser.tab.h" 25*4882a593Smuzhiyun 26*4882a593Smuzhiyun extern bool treesource_error; 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun /* CAUTION: this will stop working if we ever use yyless() or yyunput() */ 29*4882a593Smuzhiyun #define YY_USER_ACTION \ 30*4882a593Smuzhiyun { \ 31*4882a593Smuzhiyun srcpos_update(&yylloc, yytext, yyleng); \ 32*4882a593Smuzhiyun } 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun /*#define LEXDEBUG 1*/ 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun #ifdef LEXDEBUG 37*4882a593Smuzhiyun #define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) 38*4882a593Smuzhiyun #else 39*4882a593Smuzhiyun #define DPRINT(fmt, ...) do { } while (0) 40*4882a593Smuzhiyun #endif 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun static int dts_version = 1; 43*4882a593Smuzhiyun 44*4882a593Smuzhiyun #define BEGIN_DEFAULT() DPRINT("<V1>\n"); \ 45*4882a593Smuzhiyun BEGIN(V1); \ 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun static void push_input_file(const char *filename); 48*4882a593Smuzhiyun static bool pop_input_file(void); 49*4882a593Smuzhiyun static void PRINTF(1, 2) lexical_error(const char *fmt, ...); 50*4882a593Smuzhiyun 51*4882a593Smuzhiyun %} 52*4882a593Smuzhiyun 53*4882a593Smuzhiyun %% 54*4882a593Smuzhiyun <*>"/include/"{WS}*{STRING} { 55*4882a593Smuzhiyun char *name = strchr(yytext, '\"') + 1; 56*4882a593Smuzhiyun yytext[yyleng-1] = '\0'; 57*4882a593Smuzhiyun push_input_file(name); 58*4882a593Smuzhiyun } 59*4882a593Smuzhiyun 60*4882a593Smuzhiyun <*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { 61*4882a593Smuzhiyun char *line, *fnstart, *fnend; 62*4882a593Smuzhiyun struct data fn; 63*4882a593Smuzhiyun /* skip text before line # */ 64*4882a593Smuzhiyun line = yytext; 65*4882a593Smuzhiyun while (!isdigit((unsigned char)*line)) 66*4882a593Smuzhiyun line++; 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun /* regexp ensures that first and list " 69*4882a593Smuzhiyun * in the whole yytext are those at 70*4882a593Smuzhiyun * beginning and end of the filename string */ 71*4882a593Smuzhiyun fnstart = memchr(yytext, '"', yyleng); 72*4882a593Smuzhiyun for (fnend = yytext + yyleng - 1; 73*4882a593Smuzhiyun *fnend != '"'; fnend--) 74*4882a593Smuzhiyun ; 75*4882a593Smuzhiyun assert(fnstart && fnend && (fnend > fnstart)); 76*4882a593Smuzhiyun 77*4882a593Smuzhiyun fn = data_copy_escape_string(fnstart + 1, 78*4882a593Smuzhiyun fnend - fnstart - 1); 79*4882a593Smuzhiyun 80*4882a593Smuzhiyun /* Don't allow nuls in filenames */ 81*4882a593Smuzhiyun if (memchr(fn.val, '\0', fn.len - 1)) 82*4882a593Smuzhiyun lexical_error("nul in line number directive"); 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun /* -1 since #line is the number of the next line */ 85*4882a593Smuzhiyun srcpos_set_line(xstrdup(fn.val), atoi(line) - 1); 86*4882a593Smuzhiyun data_free(fn); 87*4882a593Smuzhiyun } 88*4882a593Smuzhiyun 89*4882a593Smuzhiyun <*><<EOF>> { 90*4882a593Smuzhiyun if (!pop_input_file()) { 91*4882a593Smuzhiyun yyterminate(); 92*4882a593Smuzhiyun } 93*4882a593Smuzhiyun } 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun <*>{STRING} { 96*4882a593Smuzhiyun DPRINT("String: %s\n", yytext); 97*4882a593Smuzhiyun yylval.data = data_copy_escape_string(yytext+1, 98*4882a593Smuzhiyun yyleng-2); 99*4882a593Smuzhiyun return DT_STRING; 100*4882a593Smuzhiyun } 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun <*>"/dts-v1/" { 103*4882a593Smuzhiyun DPRINT("Keyword: /dts-v1/\n"); 104*4882a593Smuzhiyun dts_version = 1; 105*4882a593Smuzhiyun BEGIN_DEFAULT(); 106*4882a593Smuzhiyun return DT_V1; 107*4882a593Smuzhiyun } 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun <*>"/plugin/" { 110*4882a593Smuzhiyun DPRINT("Keyword: /plugin/\n"); 111*4882a593Smuzhiyun return DT_PLUGIN; 112*4882a593Smuzhiyun } 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun <*>"/memreserve/" { 115*4882a593Smuzhiyun DPRINT("Keyword: /memreserve/\n"); 116*4882a593Smuzhiyun BEGIN_DEFAULT(); 117*4882a593Smuzhiyun return DT_MEMRESERVE; 118*4882a593Smuzhiyun } 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun <*>"/bits/" { 121*4882a593Smuzhiyun DPRINT("Keyword: /bits/\n"); 122*4882a593Smuzhiyun BEGIN_DEFAULT(); 123*4882a593Smuzhiyun return DT_BITS; 124*4882a593Smuzhiyun } 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun <*>"/delete-property/" { 127*4882a593Smuzhiyun DPRINT("Keyword: /delete-property/\n"); 128*4882a593Smuzhiyun DPRINT("<PROPNODENAME>\n"); 129*4882a593Smuzhiyun BEGIN(PROPNODENAME); 130*4882a593Smuzhiyun return DT_DEL_PROP; 131*4882a593Smuzhiyun } 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun <*>"/delete-node/" { 134*4882a593Smuzhiyun DPRINT("Keyword: /delete-node/\n"); 135*4882a593Smuzhiyun DPRINT("<PROPNODENAME>\n"); 136*4882a593Smuzhiyun BEGIN(PROPNODENAME); 137*4882a593Smuzhiyun return DT_DEL_NODE; 138*4882a593Smuzhiyun } 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun <*>"/omit-if-no-ref/" { 141*4882a593Smuzhiyun DPRINT("Keyword: /omit-if-no-ref/\n"); 142*4882a593Smuzhiyun DPRINT("<PROPNODENAME>\n"); 143*4882a593Smuzhiyun BEGIN(PROPNODENAME); 144*4882a593Smuzhiyun return DT_OMIT_NO_REF; 145*4882a593Smuzhiyun } 146*4882a593Smuzhiyun 147*4882a593Smuzhiyun <*>{LABEL}: { 148*4882a593Smuzhiyun DPRINT("Label: %s\n", yytext); 149*4882a593Smuzhiyun yylval.labelref = xstrdup(yytext); 150*4882a593Smuzhiyun yylval.labelref[yyleng-1] = '\0'; 151*4882a593Smuzhiyun return DT_LABEL; 152*4882a593Smuzhiyun } 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun <V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? { 155*4882a593Smuzhiyun char *e; 156*4882a593Smuzhiyun DPRINT("Integer Literal: '%s'\n", yytext); 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun errno = 0; 159*4882a593Smuzhiyun yylval.integer = strtoull(yytext, &e, 0); 160*4882a593Smuzhiyun 161*4882a593Smuzhiyun if (*e && e[strspn(e, "UL")]) { 162*4882a593Smuzhiyun lexical_error("Bad integer literal '%s'", 163*4882a593Smuzhiyun yytext); 164*4882a593Smuzhiyun } 165*4882a593Smuzhiyun 166*4882a593Smuzhiyun if (errno == ERANGE) 167*4882a593Smuzhiyun lexical_error("Integer literal '%s' out of range", 168*4882a593Smuzhiyun yytext); 169*4882a593Smuzhiyun else 170*4882a593Smuzhiyun /* ERANGE is the only strtoull error triggerable 171*4882a593Smuzhiyun * by strings matching the pattern */ 172*4882a593Smuzhiyun assert(errno == 0); 173*4882a593Smuzhiyun return DT_LITERAL; 174*4882a593Smuzhiyun } 175*4882a593Smuzhiyun 176*4882a593Smuzhiyun <*>{CHAR_LITERAL} { 177*4882a593Smuzhiyun struct data d; 178*4882a593Smuzhiyun DPRINT("Character literal: %s\n", yytext); 179*4882a593Smuzhiyun 180*4882a593Smuzhiyun d = data_copy_escape_string(yytext+1, yyleng-2); 181*4882a593Smuzhiyun if (d.len == 1) { 182*4882a593Smuzhiyun lexical_error("Empty character literal"); 183*4882a593Smuzhiyun yylval.integer = 0; 184*4882a593Smuzhiyun } else { 185*4882a593Smuzhiyun yylval.integer = (unsigned char)d.val[0]; 186*4882a593Smuzhiyun 187*4882a593Smuzhiyun if (d.len > 2) 188*4882a593Smuzhiyun lexical_error("Character literal has %d" 189*4882a593Smuzhiyun " characters instead of 1", 190*4882a593Smuzhiyun d.len - 1); 191*4882a593Smuzhiyun } 192*4882a593Smuzhiyun 193*4882a593Smuzhiyun data_free(d); 194*4882a593Smuzhiyun return DT_CHAR_LITERAL; 195*4882a593Smuzhiyun } 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun <*>\&{LABEL} { /* label reference */ 198*4882a593Smuzhiyun DPRINT("Ref: %s\n", yytext+1); 199*4882a593Smuzhiyun yylval.labelref = xstrdup(yytext+1); 200*4882a593Smuzhiyun return DT_LABEL_REF; 201*4882a593Smuzhiyun } 202*4882a593Smuzhiyun 203*4882a593Smuzhiyun <*>"&{/"{PATHCHAR}*\} { /* new-style path reference */ 204*4882a593Smuzhiyun yytext[yyleng-1] = '\0'; 205*4882a593Smuzhiyun DPRINT("Ref: %s\n", yytext+2); 206*4882a593Smuzhiyun yylval.labelref = xstrdup(yytext+2); 207*4882a593Smuzhiyun return DT_PATH_REF; 208*4882a593Smuzhiyun } 209*4882a593Smuzhiyun 210*4882a593Smuzhiyun <BYTESTRING>[0-9a-fA-F]{2} { 211*4882a593Smuzhiyun yylval.byte = strtol(yytext, NULL, 16); 212*4882a593Smuzhiyun DPRINT("Byte: %02x\n", (int)yylval.byte); 213*4882a593Smuzhiyun return DT_BYTE; 214*4882a593Smuzhiyun } 215*4882a593Smuzhiyun 216*4882a593Smuzhiyun <BYTESTRING>"]" { 217*4882a593Smuzhiyun DPRINT("/BYTESTRING\n"); 218*4882a593Smuzhiyun BEGIN_DEFAULT(); 219*4882a593Smuzhiyun return ']'; 220*4882a593Smuzhiyun } 221*4882a593Smuzhiyun 222*4882a593Smuzhiyun <PROPNODENAME>\\?{PROPNODECHAR}+ { 223*4882a593Smuzhiyun DPRINT("PropNodeName: %s\n", yytext); 224*4882a593Smuzhiyun yylval.propnodename = xstrdup((yytext[0] == '\\') ? 225*4882a593Smuzhiyun yytext + 1 : yytext); 226*4882a593Smuzhiyun BEGIN_DEFAULT(); 227*4882a593Smuzhiyun return DT_PROPNODENAME; 228*4882a593Smuzhiyun } 229*4882a593Smuzhiyun 230*4882a593Smuzhiyun "/incbin/" { 231*4882a593Smuzhiyun DPRINT("Binary Include\n"); 232*4882a593Smuzhiyun return DT_INCBIN; 233*4882a593Smuzhiyun } 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun <*>{WS}+ /* eat whitespace */ 236*4882a593Smuzhiyun <*>{COMMENT}+ /* eat C-style comments */ 237*4882a593Smuzhiyun <*>{LINECOMMENT}+ /* eat C++-style comments */ 238*4882a593Smuzhiyun 239*4882a593Smuzhiyun <*>"<<" { return DT_LSHIFT; }; 240*4882a593Smuzhiyun <*>">>" { return DT_RSHIFT; }; 241*4882a593Smuzhiyun <*>"<=" { return DT_LE; }; 242*4882a593Smuzhiyun <*>">=" { return DT_GE; }; 243*4882a593Smuzhiyun <*>"==" { return DT_EQ; }; 244*4882a593Smuzhiyun <*>"!=" { return DT_NE; }; 245*4882a593Smuzhiyun <*>"&&" { return DT_AND; }; 246*4882a593Smuzhiyun <*>"||" { return DT_OR; }; 247*4882a593Smuzhiyun 248*4882a593Smuzhiyun <*>. { 249*4882a593Smuzhiyun DPRINT("Char: %c (\\x%02x)\n", yytext[0], 250*4882a593Smuzhiyun (unsigned)yytext[0]); 251*4882a593Smuzhiyun if (yytext[0] == '[') { 252*4882a593Smuzhiyun DPRINT("<BYTESTRING>\n"); 253*4882a593Smuzhiyun BEGIN(BYTESTRING); 254*4882a593Smuzhiyun } 255*4882a593Smuzhiyun if ((yytext[0] == '{') 256*4882a593Smuzhiyun || (yytext[0] == ';')) { 257*4882a593Smuzhiyun DPRINT("<PROPNODENAME>\n"); 258*4882a593Smuzhiyun BEGIN(PROPNODENAME); 259*4882a593Smuzhiyun } 260*4882a593Smuzhiyun return yytext[0]; 261*4882a593Smuzhiyun } 262*4882a593Smuzhiyun 263*4882a593Smuzhiyun %% 264*4882a593Smuzhiyun 265*4882a593Smuzhiyun static void push_input_file(const char *filename) 266*4882a593Smuzhiyun { 267*4882a593Smuzhiyun assert(filename); 268*4882a593Smuzhiyun 269*4882a593Smuzhiyun srcfile_push(filename); 270*4882a593Smuzhiyun 271*4882a593Smuzhiyun yyin = current_srcfile->f; 272*4882a593Smuzhiyun 273*4882a593Smuzhiyun yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE)); 274*4882a593Smuzhiyun } 275*4882a593Smuzhiyun 276*4882a593Smuzhiyun 277*4882a593Smuzhiyun static bool pop_input_file(void) 278*4882a593Smuzhiyun { 279*4882a593Smuzhiyun if (srcfile_pop() == 0) 280*4882a593Smuzhiyun return false; 281*4882a593Smuzhiyun 282*4882a593Smuzhiyun yypop_buffer_state(); 283*4882a593Smuzhiyun yyin = current_srcfile->f; 284*4882a593Smuzhiyun 285*4882a593Smuzhiyun return true; 286*4882a593Smuzhiyun } 287*4882a593Smuzhiyun 288*4882a593Smuzhiyun static void lexical_error(const char *fmt, ...) 289*4882a593Smuzhiyun { 290*4882a593Smuzhiyun va_list ap; 291*4882a593Smuzhiyun 292*4882a593Smuzhiyun va_start(ap, fmt); 293*4882a593Smuzhiyun srcpos_verror(&yylloc, "Lexical error", fmt, ap); 294*4882a593Smuzhiyun va_end(ap); 295*4882a593Smuzhiyun 296*4882a593Smuzhiyun treesource_error = true; 297*4882a593Smuzhiyun } 298