Merge pull request #859 from smunaut/ice40_braminit
[yosys.git] / frontends / verilog / verilog_lexer.l
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * ---
19 *
20 * The Verilog frontend.
21 *
22 * This frontend is using the AST frontend library (see frontends/ast/).
23 * Thus this frontend does not generate RTLIL code directly but creates an
24 * AST directly from the Verilog parse tree and then passes this AST to
25 * the AST frontend library.
26 *
27 * ---
28 *
29 * A simple lexer for Verilog code. Non-preprocessor compiler directives are
30 * handled here. The preprocessor stuff is handled in preproc.cc. Everything
31 * else is left to the bison parser (see parser.y).
32 *
33 */
34
35 %{
36
37 #ifdef __clang__
38 // bison generates code using the 'register' storage class specifier
39 #pragma clang diagnostic ignored "-Wdeprecated-register"
40 #endif
41
42 #include "kernel/log.h"
43 #include "frontends/verilog/verilog_frontend.h"
44 #include "frontends/ast/ast.h"
45 #include "verilog_parser.tab.hh"
46
47 USING_YOSYS_NAMESPACE
48 using namespace AST;
49 using namespace VERILOG_FRONTEND;
50
51 YOSYS_NAMESPACE_BEGIN
52 namespace VERILOG_FRONTEND {
53 std::vector<std::string> fn_stack;
54 std::vector<int> ln_stack;
55 }
56 YOSYS_NAMESPACE_END
57
58 #define SV_KEYWORD(_tok) \
59 if (sv_mode) return _tok; \
60 log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\
61 "recognized unless read_verilog is called with -sv!\n", yytext, \
62 AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \
63 frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \
64 return TOK_ID;
65
66 #define NON_KEYWORD() \
67 frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \
68 return TOK_ID;
69
70 #define YY_INPUT(buf,result,max_size) \
71 result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
72
73 %}
74
75 %option yylineno
76 %option noyywrap
77 %option nounput
78 %option prefix="frontend_verilog_yy"
79
80 %x COMMENT
81 %x STRING
82 %x SYNOPSYS_TRANSLATE_OFF
83 %x SYNOPSYS_FLAGS
84 %x IMPORT_DPI
85
86 %%
87
88 <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* {
89 fn_stack.push_back(current_filename);
90 ln_stack.push_back(frontend_verilog_yyget_lineno());
91 current_filename = yytext+11;
92 if (!current_filename.empty() && current_filename.front() == '"')
93 current_filename = current_filename.substr(1);
94 if (!current_filename.empty() && current_filename.back() == '"')
95 current_filename = current_filename.substr(0, current_filename.size()-1);
96 frontend_verilog_yyset_lineno(0);
97 }
98
99 <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n {
100 current_filename = fn_stack.back();
101 fn_stack.pop_back();
102 frontend_verilog_yyset_lineno(ln_stack.back());
103 ln_stack.pop_back();
104 }
105
106 <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n {
107 char *p = yytext + 5;
108 while (*p == ' ' || *p == '\t') p++;
109 frontend_verilog_yyset_lineno(atoi(p));
110 while (*p && *p != ' ' && *p != '\t') p++;
111 while (*p == ' ' || *p == '\t') p++;
112 char *q = *p ? p + 1 : p;
113 while (*q && *q != '"') q++;
114 current_filename = std::string(p).substr(1, q-p-1);
115 }
116
117 "`file_notfound "[^\n]* {
118 log_error("Can't open include file `%s'!\n", yytext + 15);
119 }
120
121 "`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
122
123 "`celldefine"[^\n]* /* ignore `celldefine */
124 "`endcelldefine"[^\n]* /* ignore `endcelldefine */
125
126 "`default_nettype"[ \t]+[^ \t\r\n/]+ {
127 char *p = yytext;
128 while (*p != 0 && *p != ' ' && *p != '\t') p++;
129 while (*p == ' ' || *p == '\t') p++;
130 if (!strcmp(p, "none"))
131 VERILOG_FRONTEND::default_nettype_wire = false;
132 else if (!strcmp(p, "wire"))
133 VERILOG_FRONTEND::default_nettype_wire = true;
134 else
135 frontend_verilog_yyerror("Unsupported default nettype: %s", p);
136 }
137
138 "`protect"[^\n]* /* ignore `protect*/
139 "`endprotect"[^\n]* /* ignore `endprotect*/
140
141 "`"[a-zA-Z_$][a-zA-Z0-9_$]* {
142 frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
143 }
144
145 "module" { return TOK_MODULE; }
146 "endmodule" { return TOK_ENDMODULE; }
147 "function" { return TOK_FUNCTION; }
148 "endfunction" { return TOK_ENDFUNCTION; }
149 "task" { return TOK_TASK; }
150 "endtask" { return TOK_ENDTASK; }
151 "specify" { return TOK_SPECIFY; }
152 "endspecify" { return TOK_ENDSPECIFY; }
153 "specparam" { return TOK_SPECPARAM; }
154 "package" { SV_KEYWORD(TOK_PACKAGE); }
155 "endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
156 "interface" { SV_KEYWORD(TOK_INTERFACE); }
157 "endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); }
158 "modport" { SV_KEYWORD(TOK_MODPORT); }
159 "parameter" { return TOK_PARAMETER; }
160 "localparam" { return TOK_LOCALPARAM; }
161 "defparam" { return TOK_DEFPARAM; }
162 "assign" { return TOK_ASSIGN; }
163 "always" { return TOK_ALWAYS; }
164 "initial" { return TOK_INITIAL; }
165 "begin" { return TOK_BEGIN; }
166 "end" { return TOK_END; }
167 "if" { return TOK_IF; }
168 "else" { return TOK_ELSE; }
169 "for" { return TOK_FOR; }
170 "posedge" { return TOK_POSEDGE; }
171 "negedge" { return TOK_NEGEDGE; }
172 "or" { return TOK_OR; }
173 "case" { return TOK_CASE; }
174 "casex" { return TOK_CASEX; }
175 "casez" { return TOK_CASEZ; }
176 "endcase" { return TOK_ENDCASE; }
177 "default" { return TOK_DEFAULT; }
178 "generate" { return TOK_GENERATE; }
179 "endgenerate" { return TOK_ENDGENERATE; }
180 "while" { return TOK_WHILE; }
181 "repeat" { return TOK_REPEAT; }
182 "automatic" { return TOK_AUTOMATIC; }
183
184 "unique" { SV_KEYWORD(TOK_UNIQUE); }
185 "unique0" { SV_KEYWORD(TOK_UNIQUE); }
186 "priority" { SV_KEYWORD(TOK_PRIORITY); }
187
188 "always_comb" { SV_KEYWORD(TOK_ALWAYS); }
189 "always_ff" { SV_KEYWORD(TOK_ALWAYS); }
190 "always_latch" { SV_KEYWORD(TOK_ALWAYS); }
191
192 /* parse labels on assert, assume, cover, and restrict right here because it's insanley complex
193 to do it in the parser (because we force the parser too early to reduce when parsing cells..) */
194 ([a-zA-Z_$][a-zA-Z0-9_$]*[ \t\r\n]*:[ \t\r\n]*)?(assert|assume|cover|restrict)/[^a-zA-Z0-9_$\.] {
195 frontend_verilog_yylval.string = new std::string(yytext);
196 auto &str = *frontend_verilog_yylval.string;
197 std::string keyword;
198 int cursor = 0;
199
200 while (1) {
201 if (cursor == GetSize(str)) {
202 keyword = str;
203 delete frontend_verilog_yylval.string;
204 frontend_verilog_yylval.string = nullptr;
205 goto sva_without_label;
206 }
207 char c = str[cursor];
208 if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') {
209 cursor++;
210 continue;
211 }
212
213 keyword = str.substr(cursor);
214 str = "\\" + str.substr(0, cursor);
215 break;
216 }
217
218 cursor = 0;
219 while (1) {
220 log_assert(cursor < GetSize(keyword));
221 char c = keyword[cursor];
222 if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') {
223 keyword = keyword.substr(cursor);
224 break;
225 }
226 cursor++;
227 }
228
229 if (keyword == "assert") { return TOK_ASSERT; }
230 else if (keyword == "assume") { return TOK_ASSUME; }
231 else if (keyword == "cover") { return TOK_COVER; }
232 else if (keyword == "restrict") { return TOK_RESTRICT; }
233 else log_abort();
234
235 sva_without_label:
236 if (keyword == "assert") { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
237 else if (keyword == "assume") { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
238 else if (keyword == "cover") { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
239 else if (keyword == "restrict") { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
240 else log_abort();
241 }
242
243 "property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
244 "rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); }
245 "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
246 "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
247 "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
248 "logic" { SV_KEYWORD(TOK_LOGIC); }
249 "bit" { SV_KEYWORD(TOK_REG); }
250
251 "eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
252 "s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
253
254 "input" { return TOK_INPUT; }
255 "output" { return TOK_OUTPUT; }
256 "inout" { return TOK_INOUT; }
257 "wire" { return TOK_WIRE; }
258 "reg" { return TOK_REG; }
259 "integer" { return TOK_INTEGER; }
260 "signed" { return TOK_SIGNED; }
261 "genvar" { return TOK_GENVAR; }
262 "real" { return TOK_REAL; }
263
264 "enum" { SV_KEYWORD(TOK_ENUM); }
265 "typedef" { SV_KEYWORD(TOK_TYPEDEF); }
266
267 [0-9][0-9_]* {
268 frontend_verilog_yylval.string = new std::string(yytext);
269 return TOK_CONSTVAL;
270 }
271
272 [0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
273 frontend_verilog_yylval.string = new std::string(yytext);
274 return TOK_CONSTVAL;
275 }
276
277 [0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? {
278 frontend_verilog_yylval.string = new std::string(yytext);
279 return TOK_REALVAL;
280 }
281
282 [0-9][0-9_]*[eE][-+]?[0-9_]+ {
283 frontend_verilog_yylval.string = new std::string(yytext);
284 return TOK_REALVAL;
285 }
286
287 \" { BEGIN(STRING); }
288 <STRING>\\. { yymore(); }
289 <STRING>\" {
290 BEGIN(0);
291 char *yystr = strdup(yytext);
292 yystr[strlen(yytext) - 1] = 0;
293 int i = 0, j = 0;
294 while (yystr[i]) {
295 if (yystr[i] == '\\' && yystr[i + 1]) {
296 i++;
297 if (yystr[i] == 'a')
298 yystr[i] = '\a';
299 else if (yystr[i] == 'f')
300 yystr[i] = '\f';
301 else if (yystr[i] == 'n')
302 yystr[i] = '\n';
303 else if (yystr[i] == 'r')
304 yystr[i] = '\r';
305 else if (yystr[i] == 't')
306 yystr[i] = '\t';
307 else if (yystr[i] == 'v')
308 yystr[i] = '\v';
309 else if ('0' <= yystr[i] && yystr[i] <= '7') {
310 yystr[i] = yystr[i] - '0';
311 if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
312 yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
313 i++;
314 }
315 if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
316 yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
317 i++;
318 }
319 }
320 }
321 yystr[j++] = yystr[i++];
322 }
323 yystr[j] = 0;
324 frontend_verilog_yylval.string = new std::string(yystr, j);
325 free(yystr);
326 return TOK_STRING;
327 }
328 <STRING>. { yymore(); }
329
330 and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
331 frontend_verilog_yylval.string = new std::string(yytext);
332 return TOK_PRIMITIVE;
333 }
334
335 supply0 { return TOK_SUPPLY0; }
336 supply1 { return TOK_SUPPLY1; }
337
338 "$"(display|write|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
339 frontend_verilog_yylval.string = new std::string(yytext);
340 return TOK_ID;
341 }
342
343 "$signed" { return TOK_TO_SIGNED; }
344 "$unsigned" { return TOK_TO_UNSIGNED; }
345
346 [a-zA-Z_$][a-zA-Z0-9_$]* {
347 frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
348 return TOK_ID;
349 }
350
351 [a-zA-Z_$][a-zA-Z0-9_$\.]* {
352 frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
353 return TOK_ID;
354 }
355
356 "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
357 static bool printed_warning = false;
358 if (!printed_warning) {
359 log_warning("Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n"
360 "Yosys does support them but it is recommended to use `ifdef constructs instead!\n");
361 printed_warning = true;
362 }
363 BEGIN(SYNOPSYS_TRANSLATE_OFF);
364 }
365 <SYNOPSYS_TRANSLATE_OFF>. /* ignore synopsys translate_off body */
366 <SYNOPSYS_TRANSLATE_OFF>\n /* ignore synopsys translate_off body */
367 <SYNOPSYS_TRANSLATE_OFF>"/*"[ \t]*(synopsys|synthesis)[ \t]*"translate_on"[ \t]*"*/" { BEGIN(0); }
368
369 "/*"[ \t]*(synopsys|synthesis)[ \t]+ {
370 BEGIN(SYNOPSYS_FLAGS);
371 }
372 <SYNOPSYS_FLAGS>full_case {
373 static bool printed_warning = false;
374 if (!printed_warning) {
375 log_warning("Found one of those horrible `(synopsys|synthesis) full_case' comments.\n"
376 "Yosys does support them but it is recommended to use Verilog `full_case' attributes instead!\n");
377 printed_warning = true;
378 }
379 return TOK_SYNOPSYS_FULL_CASE;
380 }
381 <SYNOPSYS_FLAGS>parallel_case {
382 static bool printed_warning = false;
383 if (!printed_warning) {
384 log_warning("Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n"
385 "Yosys does support them but it is recommended to use Verilog `parallel_case' attributes instead!\n");
386 printed_warning = true;
387 }
388 return TOK_SYNOPSYS_PARALLEL_CASE;
389 }
390 <SYNOPSYS_FLAGS>. /* ignore everything else */
391 <SYNOPSYS_FLAGS>"*/" { BEGIN(0); }
392
393 import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
394 BEGIN(IMPORT_DPI);
395 return TOK_DPI_FUNCTION;
396 }
397
398 <IMPORT_DPI>[a-zA-Z_$][a-zA-Z0-9_$]* {
399 frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
400 return TOK_ID;
401 }
402
403 <IMPORT_DPI>[ \t\r\n] /* ignore whitespaces */
404
405 <IMPORT_DPI>";" {
406 BEGIN(0);
407 return *yytext;
408 }
409
410 <IMPORT_DPI>. {
411 return *yytext;
412 }
413
414 "\\"[^ \t\r\n]+ {
415 frontend_verilog_yylval.string = new std::string(yytext);
416 return TOK_ID;
417 }
418
419 "(*" { return ATTR_BEGIN; }
420 "*)" { return ATTR_END; }
421
422 "{*" { return DEFATTR_BEGIN; }
423 "*}" { return DEFATTR_END; }
424
425 "**" { return OP_POW; }
426 "||" { return OP_LOR; }
427 "&&" { return OP_LAND; }
428 "==" { return OP_EQ; }
429 "!=" { return OP_NE; }
430 "<=" { return OP_LE; }
431 ">=" { return OP_GE; }
432
433 "===" { return OP_EQX; }
434 "!==" { return OP_NEX; }
435
436 "~&" { return OP_NAND; }
437 "~|" { return OP_NOR; }
438 "~^" { return OP_XNOR; }
439 "^~" { return OP_XNOR; }
440
441 "<<" { return OP_SHL; }
442 ">>" { return OP_SHR; }
443 "<<<" { return OP_SSHL; }
444 ">>>" { return OP_SSHR; }
445
446 "::" { return TOK_PACKAGESEP; }
447 "++" { return TOK_INCREMENT; }
448 "--" { return TOK_DECREMENT; }
449
450 "+:" { return TOK_POS_INDEXED; }
451 "-:" { return TOK_NEG_INDEXED; }
452
453 "/*" { BEGIN(COMMENT); }
454 <COMMENT>. /* ignore comment body */
455 <COMMENT>\n /* ignore comment body */
456 <COMMENT>"*/" { BEGIN(0); }
457
458 [ \t\r\n] /* ignore whitespaces */
459 \\[\r\n] /* ignore continuation sequence */
460 "//"[^\r\n]* /* ignore one-line comments */
461
462 . { return *yytext; }
463
464 %%
465
466 // this is a hack to avoid the 'yyinput defined but not used' error msgs
467 void *frontend_verilog_avoid_input_warnings() {
468 return (void*)&yyinput;
469 }
470