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