網站首頁 編程語言 正文
目錄
- lex/yacc&C++使用及學習記錄
- 一、準備工作
- 二 、編譯過程
- 三、代碼編寫注意事項
- 四、踩到的一些坑
lex/yacc&C++使用及學習記錄
(寫在前面的話)本文是筆者在工作項目中實際使用到的lex/yacc的記錄,主要介紹的是項目中如何組織、編譯以及遇到的一些問題。不會提到一些十分基礎的知識。如果需要學習基礎知識可以移步去看o’reilly的書。
一、準備工作
使用lex yacc和C++一起實現功能時,需要建立四個文件來進行調用,即.l、.y、.cpp和.h文件。
xxxLexer.cpp (MyxxxLexer中的函數具體實現,需要重載yyFlexLexer中的一些函數)
xxxLexer.h (繼承yyFlexLexer生成一個新的類MyxxxLexer)
xxxLexer.l (lex 詞法分析器實現)
xxxParser.y (yacc語法分析器實現)
yyFlexLexer是繼承自FlexLexer的一個類,其中有諸多接口,這個類會在.l和.y文件編譯后存在與C代碼中,這里貼一個之前看到的類文檔頁面,里面介紹了涉及到的一些接口,以作參考
casa: yyFlexLexer Class Reference (nrao.edu)
二 、編譯過程
lex yacc需要生成一些C源代碼(.cxx、.hxx)來使用,所以如果是在一個項目中進行編譯,需要在CMakeLists中添加FLEX_TARGET和BISON_TARGET
FLEX_TARGET(xxxScanner xxxLexer.l ${CMAKE_CURRENT_BINARY_DIR}/xxxLexer.cxx)
BISON_TARGET(xxxParser xxxParser.y ${CMAKE_CURRENT_BINARY_DIR}/xxxParser.cxx
COMPILE_FLAGS -v DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/xxxPraser.hxx)
ADD_FLEX_BISON_DEPENDENCY(xxxScanner xxxParser) # 這里一定要把Scanner放在前面
三、代碼編寫注意事項
.l文件的編寫中沒太多需要注意的東西,唯一需要注意的是一些option
%option noyywrap
%option c++
%option prefix="xxx" //表示生成的lexyacc的C代碼中所有yy開頭的函數和類都會變為xxx開頭
.y文件中
①數據類型的定義,可以使用union來進行,也可以使用#define YYSTYPE type來進行,這個type可以是C的基本類型,也可以是自己定義的指針或自己定義的struct等,但是要在定義段聲明或者指定命名空間才能在union中使用。如果沒有定義的話,yacc中傳遞的數據默認為int。
②在.y中可以重寫yylex等函數,調用cpp中自己生成的類對象,以將lex詞法分析獲取的信息賦給自己定義的數據類型,從而能作為參數用于語法分析中。
③在編寫規則時,不同的兩條規則直之間會有一些規約沖突,可能是編寫的規則有重復的部分,需要對其進行尋找并修改。//定義段,引入頭文件、數據類型等等定義
%{
#define yyFlexLexer xxxFlexLexer
#include <FlexLexer.h>
#include <string.h>
#include "xxxLexer.h"
#include "xxxParser.hxx"
#include <iostream>
#define CUR_LEXER static_cast<MyxxxLexer*>(_param)
//這里define后,規則段可以調用對象里的函數,調用方式為CUR_LEXER->函數名()
%}
// 定義數據類型
%union
{
int *_value;
char *_op ;
}
%{
int yylex(YYSTYPE *yyvalp, ...) // 可以在這里重寫yylex函數
{
auto lexer = static_case<MyxxxLexer*>(_param);
int res = lexer.yylex(); // 好像是這么寫的 如果有問題我后面再回來改改
}
// 這個函數的返回值是.l中返回的類型所對應的整型值
%}
%token <_value> VALUE
%token<_op> OP
%%
// 規則段
%%
// 自定義函數段
.h與.cpp中
如果同一個目錄下的代碼已經有另一些cpp代碼定義過,即#define yyFlexLexer zzzFlexLexer,需要在.h頭文件中寫以下代碼以避免繼承yyFlexLexer的報錯,讓代碼知道自己繼承的是哪個yyFlexLexer
#if !defined(yyFlexLexerOnce)
#undef yyFlexLexer // 注意拼寫正確 如果拼寫錯誤編譯時會出現鏈接不到的錯誤
#define yyFlexLexer xxxFlexLexer
#include <FlexLexer.h>
#endif
// 如果這里沒重新定義自己的xxxFlexLexer,會在類定義的地方報error: expected class-name before ‘{’ token的錯
一個編寫模板如下:
/*.h文件中的類和接口定義*/
class MyxxxLexer : public yyFlexLexer
{
public:
// Construct function
MyxxxLexer(const char *data) {}
virtual ~MyxxxLexer() {}
// 一些yyFlexLexer中的虛函數,可以重寫以實現自己的功能
virtual int LexerInput(char* buf, int max_size); // 讀取數據用于詞法語法分析
virtual void LexerError(const char* msg);
// 自己可以定義一些接口,在.y文件中可以實例化,以在規則段用于調用
private:
// 自己定義的數據
};
void processFuncLexer(const char *data, MyxxxLexer *funcLexer);
//自定義一個接口,目的是告訴編譯器,調用這個函數的時候,開始對自己輸入的數據進行解析
/*.cpp文件中的實現*/
extern int xxxparse(void*); // 這里的外部調用函數,叫xxxparse,是因為之前prefix定義為了xxx
void processFuncLexer(const char *func, MyxxxLexer *funcLexer)
{ xxxparse(funcLexer); }
int YFuncLexer::LexerInput(char* buf, int max_size)
{
// char _str是自己定義的數據類型,這個函數的目的就是把數據放到buf中,傳給解析器
size_t num = strlen(_str) + 1
memcpy(buf, _str, num);
return num;
}
// 其余函數的實現這里不做贅述
四、踩到的一些坑
①編譯報錯
在項目其他目錄的代碼文件中使用MyxxxLexer這個類時,如果在Linking CXX executable時報錯,提示信息是undefined reference to `yyFlexLexer::yyFlexLexer(std::istream*, std::ostream*)等等,此時要首先看自己的一些宏定義是不是寫錯了,其次才是考慮CMakeLists中鏈接的問題。
②歸約錯誤,即.y中規則段編寫的注意事項,如果規則段沒有編寫好,出現了一些匹配沖突,yacc會報相關的沖突錯誤,這時需要自己尋找哪里寫得不合理,避免規則之間有沖突。
原文鏈接:https://blog.csdn.net/Rong_11/article/details/126979975
相關推薦
- 2024-07-15 項目開發中使用Date和LocalDateTime處理日期
- 2022-02-14 taro將頁面滾動到指定位置
- 2023-04-01 Python之維度dim的定義及其理解使用方式_python
- 2022-06-12 go實現grpc四種數據流模式_Golang
- 2023-01-19 詳解如何利用C#實現設置系統時間_C#教程
- 2022-09-01 ASP.NET?Core通用主機實現托管服務_實用技巧
- 2022-11-29 Rust?模式匹配示例詳解_Rust語言
- 2022-10-19 Android項目中引入aar包的正確方法介紹_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支