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