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