verilator/src/V3PreLex.h

250 lines
8.6 KiB
C++

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilog::Preproc: Internal header for lex interfacing
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2000-2024 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
// This header provides the interface between the lex proper V3PreLex.l/.cpp
// and the class implementation file V3Pre.cpp
// It is not intended for user applications.
//*************************************************************************
#ifndef VERILATOR_VPRELEX_H_ // Guard
#define VERILATOR_VPRELEX_H_
#include "V3Error.h"
#include "V3FileLine.h"
#include <deque>
#include <stack>
//======================================================================
class V3PreLex;
class V3PreProcImp;
// Token codes
// If changing, see V3PreProc.cpp's V3PreProcImp::tokenName()
// clang-format off
#define VP_EOF 0 // Must be zero, a.k.a. YY_NULL, a.k.a. yy_terminate();
#define VP_EOF_ERROR 400
#define VP_INCLUDE 256
#define VP_IFDEF 257
#define VP_IFNDEF 258
#define VP_ENDIF 259
#define VP_UNDEF 260
#define VP_DEFINE 261
#define VP_ELSE 262
#define VP_ELSIF 263
#define VP_LINE 264
#define VP_UNDEFINEALL 265
#define VP_SYMBOL 300
#define VP_STRING 301
#define VP_DEFVALUE 302
#define VP_COMMENT 303
#define VP_TEXT 304
#define VP_WHITE 305
#define VP_DEFREF 306
#define VP_DEFARG 307
#define VP_ERROR 308
#define VP_DEFFORM 309
#define VP_STRIFY 310
#define VP_BACKQUOTE 311
#define VP_SYMBOL_JOIN 312
#define VP_DEFREF_JOIN 313
#define VP_JOIN 314
#define VP_PSL 350
// clang-format on
//======================================================================
// Externs created by flex
// We add a prefix so that other lexers/flexers in the same program won't collide.
// clang-format off
#ifndef yy_create_buffer
# define yy_create_buffer V3PreLex_create_buffer
# define yy_delete_buffer V3PreLex_delete_buffer
# define yy_scan_buffer V3PreLex_scan_buffer
# define yy_scan_string V3PreLex_scan_string
# define yy_scan_bytes V3PreLex_scan_bytes
# define yy_flex_debug V3PreLex_flex_debug
# define yy_init_buffer V3PreLex_init_buffer
# define yy_flush_buffer V3PreLex_flush_buffer
# define yy_load_buffer_state V3PreLex_load_buffer_state
# define yy_switch_to_buffer V3PreLex_switch_to_buffer
# define yyin V3PreLexin
# define yyleng V3PreLexleng
# define yylex V3PreLexlex
# define yyout V3PreLexout
# define yyrestart V3PreLexrestart
# define yytext V3PreLextext
# define yyerror V3PreLexerror
# define yyerrorf V3PreLexerrorf
# define yylex_destroy V3PreLexlex_destroy
#endif
#ifndef yyourleng
# define yyourleng V3PreLexourleng
# define yyourtext V3PreLexourtext
#endif
#ifndef YY_BUFFER_STATE
struct yy_buffer_state;
typedef struct yy_buffer_state* YY_BUFFER_STATE;
# define YY_BUF_SIZE 16384
#endif
// clang-format on
extern int yylex();
extern void yyrestart(FILE*);
// Accessors, because flex keeps changing the type of yyleng
extern char* yyourtext();
extern size_t yyourleng();
extern void yyourtext(const char* textp, size_t size); // Must call with static
YY_BUFFER_STATE yy_create_buffer(FILE* file, int size);
void yy_switch_to_buffer(YY_BUFFER_STATE new_buffer);
void yy_delete_buffer(YY_BUFFER_STATE b);
int yylex_destroy();
//======================================================================
#define KEEPCMT_SUB 2
#define KEEPCMT_EXP 3
//======================================================================
// Entry for each file processed; a stack of entries included
class VPreStream final {
public:
FileLine* m_curFilelinep; // Current processing point (see also m_tokFilelinep)
V3PreLex* const m_lexp; // Lexer, for resource tracking
std::deque<string> m_buffers; // Buffer of characters to process
int m_ignNewlines = 0; // Ignore multiline newlines
int m_termState = 0; // Termination fsm
bool m_eof = false; // "EOF" buffer
bool m_file = false; // Buffer is start of new file
VPreStream(FileLine* fl, V3PreLex* lexp)
: m_curFilelinep{fl}
, m_lexp{lexp} {
lexStreamDepthAdd(1);
}
~VPreStream() { lexStreamDepthAdd(-1); }
private:
inline void lexStreamDepthAdd(int delta);
};
//======================================================================
// Enum Class for `pragma protect encoding types
enum class Enctype : uint8_t { UUENCODE, BASE64, QUOTE_PRINTABLE, RAW, ERR };
//======================================================================
// Class entry for each per-lexer state
class V3PreLex final {
public: // Used only by V3PreLex.cpp and V3PreProc.cpp
V3PreProcImp* const m_preimpp; // Preprocessor lexor belongs to
std::stack<VPreStream*> m_streampStack; // Stack of processing files
int m_streamDepth = 0; // Depth of stream processing
YY_BUFFER_STATE m_bufferState; // Flex state
FileLine* m_tokFilelinep; // Starting position of current token
std::deque<FileLine> m_lexLintState; // Current lint state for save/restore
// State to lexer
static V3PreLex* s_currentLexp; ///< Current lexing point
int m_keepComments = 0; ///< Emit comments in output text
int m_keepWhitespace = 1; ///< Emit all whitespace in output text
bool m_pedantic = false; ///< Obey standard; don't Substitute `error
// State from lexer
int m_formalLevel = 0; // Parenthesis counting inside def formals
int m_parenLevel = 0; // Parenthesis counting inside def args
bool m_defCmtSlash = false; // /*...*/ comment in define had \ ending
bool m_defQuote = false; // Definition value inside quote
string m_defValue; // Definition value being built.
int m_enterExit = 0; // For VL_LINE, the enter/exit level
int m_protLength = 0; // unencoded length for BASE64
int m_protBytes = 0; // decoded length for BASE64
Enctype m_encType{}; // encoding type for `pragma protect
// CONSTRUCTORS
V3PreLex(V3PreProcImp* preimpp, FileLine* filelinep)
: m_preimpp{preimpp}
, m_tokFilelinep{filelinep} {
initFirstBuffer(filelinep);
}
~V3PreLex() {
while (!m_streampStack.empty()) {
delete m_streampStack.top();
m_streampStack.pop();
}
VL_DO_CLEAR(yy_delete_buffer(m_bufferState), m_bufferState = nullptr);
yylex_destroy();
}
// Called by V3PreLex.l from lexer
VPreStream* curStreamp() { return m_streampStack.top(); } // Can't be empty, "EOF" is on top
FileLine* curFilelinep() { return curStreamp()->m_curFilelinep; }
void curFilelinep(FileLine* fl) { curStreamp()->m_curFilelinep = fl; }
void appendDefValue(const char* textp, size_t len) { m_defValue.append(textp, len); }
void lineDirective(const char* textp);
void linenoInc() {
if (curStreamp()->m_ignNewlines) {
curStreamp()->m_ignNewlines--;
} else {
curFilelinep()->linenoInc();
}
}
void warnBackslashSpace();
void verilatorCmtLint(const char* textp, bool warnOff);
void verilatorCmtLintRestore();
void verilatorCmtLintSave();
// Called by V3PreProc.cpp to inform lexer
void pushStateDefArg(int level);
void pushStateDefForm();
void pushStateDefValue();
void pushStateExpr();
void pushStateIncFilename();
void scanNewFile(FileLine* filelinep);
void scanBytes(const string& str);
void scanBytesBack(const string& str);
size_t inputToLex(char* buf, size_t max_size);
/// Called by V3PreProc.cpp to get data from lexer
YY_BUFFER_STATE currentBuffer();
int lex();
int currentStartState() const;
void dumpSummary();
void dumpStack();
void unused();
// Called by VPreStream
void streamDepthAdd(int delta) { m_streamDepth += delta; }
int streamDepth() const { return m_streamDepth; }
// Utility
static void setYYDebug(bool on);
static string cleanDbgStrg(const string& in);
private:
string currentUnreadChars();
string endOfStream(bool& againr);
void initFirstBuffer(FileLine* filelinep);
void scanSwitchStream(VPreStream* streamp);
};
void VPreStream::lexStreamDepthAdd(int delta) { m_lexp->streamDepthAdd(delta); }
#endif // Guard