IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> lex yacc与C++编写代码解析字符串代码示例 -> 正文阅读

[C++知识库]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, void *param) // 可以在这里重写yylex函数
{
  auto lexer = static_case<MyxxxLexer*>(_param);
  int res = lexer->yylex();  
  yyvalp->_op = strdup(lexer->YYText());  // 这样来进行赋值
  return res;
}
// 这个函数的返回值是.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会报相关的冲突错误,这时需要自己寻找哪里写得不合理,避免规则之间有冲突。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 20:38:18  更:2022-09-24 20:41:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 12:42:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码