1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //*************************************************************************
3 // DESCRIPTION: Verilog::Preproc: Internal header for lex interfacing
4 //
5 // Code available from: https://verilator.org
6 //
7 //*************************************************************************
8 //
9 // Copyright 2000-2021 by Wilson Snyder. This program is free software; you
10 // can redistribute it and/or modify it under the terms of either the GNU
11 // Lesser General Public License Version 3 or the Perl Artistic License
12 // Version 2.0.
13 // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
14 //
15 //*************************************************************************
16 // This header provides the interface between the lex proper V3PreLex.l/.cpp
17 // and the class implementation file V3Pre.cpp
18 // It is not intended for user applications.
19 //*************************************************************************
20
21 #ifndef VERILATOR_VPRELEX_H_ // Guard
22 #define VERILATOR_VPRELEX_H_
23
24 #include "V3Error.h"
25 #include "V3FileLine.h"
26
27 #include <deque>
28 #include <stack>
29
30 //======================================================================
31
32 class V3PreLex;
33 class V3PreProcImp;
34
35 // Token codes
36 // If changing, see V3PreProc.cpp's V3PreProcImp::tokenName()
37 // clang-format off
38 #define VP_EOF 0 // Must be zero, a.k.a. YY_NULL, a.k.a. yy_terminate();
39 #define VP_EOF_ERROR 400
40
41 #define VP_INCLUDE 256
42 #define VP_IFDEF 257
43 #define VP_IFNDEF 258
44 #define VP_ENDIF 259
45 #define VP_UNDEF 260
46 #define VP_DEFINE 261
47 #define VP_ELSE 262
48 #define VP_ELSIF 263
49 #define VP_LINE 264
50 #define VP_UNDEFINEALL 265
51
52 #define VP_SYMBOL 300
53 #define VP_STRING 301
54 #define VP_DEFVALUE 302
55 #define VP_COMMENT 303
56 #define VP_TEXT 304
57 #define VP_WHITE 305
58 #define VP_DEFREF 306
59 #define VP_DEFARG 307
60 #define VP_ERROR 308
61 #define VP_DEFFORM 309
62 #define VP_STRIFY 310
63 #define VP_BACKQUOTE 311
64 #define VP_SYMBOL_JOIN 312
65 #define VP_DEFREF_JOIN 313
66 #define VP_JOIN 314
67
68 #define VP_PSL 350
69 // clang-format on
70
71 //======================================================================
72 // Externs created by flex
73 // We add a prefix so that other lexers/flexers in the same program won't collide.
74
75 // clang-format off
76 #ifndef yy_create_buffer
77 # define yy_create_buffer V3PreLex_create_buffer
78 # define yy_delete_buffer V3PreLex_delete_buffer
79 # define yy_scan_buffer V3PreLex_scan_buffer
80 # define yy_scan_string V3PreLex_scan_string
81 # define yy_scan_bytes V3PreLex_scan_bytes
82 # define yy_flex_debug V3PreLex_flex_debug
83 # define yy_init_buffer V3PreLex_init_buffer
84 # define yy_flush_buffer V3PreLex_flush_buffer
85 # define yy_load_buffer_state V3PreLex_load_buffer_state
86 # define yy_switch_to_buffer V3PreLex_switch_to_buffer
87 # define yyin V3PreLexin
88 # define yyleng V3PreLexleng
89 # define yylex V3PreLexlex
90 # define yyout V3PreLexout
91 # define yyrestart V3PreLexrestart
92 # define yytext V3PreLextext
93 # define yyerror V3PreLexerror
94 # define yyerrorf V3PreLexerrorf
95 #endif
96
97 #ifndef yyourleng
98 # define yyourleng V3PreLexourleng
99 # define yyourtext V3PreLexourtext
100 #endif
101
102 #ifndef YY_BUFFER_STATE
103 struct yy_buffer_state;
104 typedef struct yy_buffer_state* YY_BUFFER_STATE;
105 # define YY_BUF_SIZE 16384
106 #endif
107 // clang-format on
108
109 extern int yylex();
110 extern void yyrestart(FILE*);
111
112 // Accessors, because flex keeps changing the type of yyleng
113 extern char* yyourtext();
114 extern size_t yyourleng();
115 extern void yyourtext(const char* textp, size_t size); // Must call with static
116
117 YY_BUFFER_STATE yy_create_buffer(FILE* file, int size);
118 void yy_switch_to_buffer(YY_BUFFER_STATE new_buffer);
119 void yy_delete_buffer(YY_BUFFER_STATE b);
120
121 //======================================================================
122
123 #define KEEPCMT_SUB 2
124 #define KEEPCMT_EXP 3
125
126 //======================================================================
127 // Entry for each file processed; a stack of entries included
128
129 class VPreStream final {
130 public:
131 FileLine* m_curFilelinep; // Current processing point (see also m_tokFilelinep)
132 V3PreLex* m_lexp; // Lexer, for resource tracking
133 std::deque<string> m_buffers; // Buffer of characters to process
134 int m_ignNewlines = 0; // Ignore multiline newlines
135 bool m_eof = false; // "EOF" buffer
136 bool m_file = false; // Buffer is start of new file
137 int m_termState = 0; // Termination fsm
VPreStream(FileLine * fl,V3PreLex * lexp)138 VPreStream(FileLine* fl, V3PreLex* lexp)
139 : m_curFilelinep{fl}
140 , m_lexp{lexp} {
141 lexStreamDepthAdd(1);
142 }
~VPreStream()143 ~VPreStream() { lexStreamDepthAdd(-1); }
144
145 private:
146 void lexStreamDepthAdd(int delta);
147 };
148
149 //======================================================================
150 // Enum Class for `pragma protect encoding types
151 enum class Enctype : uint8_t { UUENCODE, BASE64, QUOTE_PRINTABLE, RAW, ERR };
152
153 //======================================================================
154 // Class entry for each per-lexer state
155
156 class V3PreLex final {
157 public: // Used only by V3PreLex.cpp and V3PreProc.cpp
158 V3PreProcImp* m_preimpp; // Preprocessor lexor belongs to
159 std::stack<VPreStream*> m_streampStack; // Stack of processing files
160 int m_streamDepth = 0; // Depth of stream processing
161 YY_BUFFER_STATE m_bufferState; // Flex state
162 FileLine* m_tokFilelinep; // Starting position of current token
163
164 // State to lexer
165 static V3PreLex* s_currentLexp; ///< Current lexing point
166 int m_keepComments = 0; ///< Emit comments in output text
167 int m_keepWhitespace = 1; ///< Emit all whitespace in output text
168 bool m_pedantic = false; ///< Obey standard; don't Substitute `error
169
170 // State from lexer
171 int m_formalLevel = 0; // Parenthesis counting inside def formals
172 int m_parenLevel = 0; // Parenthesis counting inside def args
173 bool m_defCmtSlash = false; // /*...*/ comment in define had \ ending
174 bool m_defQuote = false; // Definition value inside quote
175 string m_defValue; // Definition value being built.
176 int m_enterExit = 0; // For VL_LINE, the enter/exit level
177 int m_protLength = 0; // unencoded length for BASE64
178 int m_protBytes = 0; // decoded length for BASE64
179 Enctype m_encType; // encoding type for `pragma protect
180
181 // CONSTRUCTORS
V3PreLex(V3PreProcImp * preimpp,FileLine * filelinep)182 V3PreLex(V3PreProcImp* preimpp, FileLine* filelinep)
183 : m_preimpp{preimpp}
184 , m_tokFilelinep{filelinep} {
185 initFirstBuffer(filelinep);
186 }
~V3PreLex()187 ~V3PreLex() {
188 while (!m_streampStack.empty()) {
189 delete m_streampStack.top();
190 m_streampStack.pop();
191 }
192 VL_DO_CLEAR(yy_delete_buffer(m_bufferState), m_bufferState = nullptr);
193 }
194
195 // Called by V3PreLex.l from lexer
curStreamp()196 VPreStream* curStreamp() { return m_streampStack.top(); } // Can't be empty, "EOF" is on top
curFilelinep()197 FileLine* curFilelinep() { return curStreamp()->m_curFilelinep; }
curFilelinep(FileLine * fl)198 void curFilelinep(FileLine* fl) { curStreamp()->m_curFilelinep = fl; }
appendDefValue(const char * textp,size_t len)199 void appendDefValue(const char* textp, size_t len) { m_defValue.append(textp, len); }
200 void lineDirective(const char* textp);
linenoInc()201 void linenoInc() {
202 if (curStreamp()->m_ignNewlines) {
203 curStreamp()->m_ignNewlines--;
204 } else {
205 curFilelinep()->linenoInc();
206 }
207 }
208 void warnBackslashSpace();
209 // Called by V3PreProc.cpp to inform lexer
210 void pushStateDefArg(int level);
211 void pushStateDefForm();
212 void pushStateDefValue();
213 void pushStateIncFilename();
214 void scanNewFile(FileLine* filelinep);
215 void scanBytes(const string& str);
216 void scanBytesBack(const string& str);
217 size_t inputToLex(char* buf, size_t max_size);
218 /// Called by V3PreProc.cpp to get data from lexer
219 YY_BUFFER_STATE currentBuffer();
220 int lex();
221 int currentStartState() const;
222 void dumpSummary();
223 void dumpStack();
224 void unused();
225 // Called by VPreStream
streamDepthAdd(int delta)226 void streamDepthAdd(int delta) { m_streamDepth += delta; }
streamDepth()227 int streamDepth() const { return m_streamDepth; }
228 /// Utility
229 static int debug();
230 static void debug(int level);
231 static string cleanDbgStrg(const string& in);
232
233 private:
234 string currentUnreadChars();
235 string endOfStream(bool& againr);
236 void initFirstBuffer(FileLine* filelinep);
237 void scanSwitchStream(VPreStream* streamp);
238 };
239
lexStreamDepthAdd(int delta)240 inline void VPreStream::lexStreamDepthAdd(int delta) { m_lexp->streamDepthAdd(delta); }
241
242 #endif // Guard
243