词法与语法分析器介绍

news2024/7/6 18:19:24

概述

词法和语法可以使用正则表达式和BNF范式表达,而最终描述文法含义的事状态转换图

Lex与YACC

词法分析器Lex

词法分析词Lex,是一种生成词法分析的工具,描述器是识别文本中词汇模式的程序,这些词汇模式是在特殊的句子结构中定义的

Lex 接收到文件或文本形式的输入时,会将文本与常规表达式进行匹配:一次读入一个输入字符,直到找到一个匹配的模式

如果能够找到一个匹配的模式,Lex就执行相关的动作(比如返回一个标记Token)。另外,如果没有可以匹配的常规表达式,将会停止停止进一步的处理,Lex将显示一个错误信息

Lex 和 C语言是强耦合的,一个.lex文件通过Lex解析并生成C的输出文件,这些文件被编译为词法分析器的可执行版本

lex 或 .l 文件在格式上分为以下3段

    1. 全局变量声明部分
    1. 词法规则部分
    1. 函数定义部分

Lex 变量表

变量名详细解释
yyinFILE* 类型。它指向lexer 正在解析的当前文件
yyoutFILE* 类型。它指向记录lexer输出的位置。默认情况下,yyin 和 yyout 都指向标准输入和输出
yytext匹配模式的文本存储在这一变量中(char*)
yyleng给出匹配模式的长度
yylineno提供当前的行数信息(lexer不一定支持)

Lex 函数表

函数名详细解释
yylex()这一函数开始分析。它由Lex自动生成
yywrap()这一函数在文件(或输入)的末尾调用。如果函数的返回值是1,就停止解析。它可以用来解析多个文件
yyless(int)这一函数可以用来输出除来前n个字符外的所有读出标记
yymore()这一函数告诉Lexer将下一个标记附加到当前标记后

代码

文件 a.l

%{
#include <stdio.h>
extern char *yytext;
extern FILE *yyin;
int count = 0;
%}

%%// 两个百分号标记指出了 Lex 程序中这一段的结束和第二段的开始
\$[a-zA-Z][a-zA-Z0-9]*  {count++; printf("  变量%s", yytext);}
[0-9\/.-]+  printf("数字%s", yytext);
=           printf("被赋值为");
\n          printf("\n");
[ \t]+      /* 忽略空格 */;
%%

// 函数定义部分
int main(int avgs, char *avgr[]) {
    yyin = fopen(avgr[1], "r");
    if (!yyin) {
        return 0;
    }

    yylex();
    printf("变量总数为:%d\n", count);
    fclose(yyin);
    return 1;
}

对于以上代码,解释如下

  • 全局变量声明部分: 声明了一个int型全局变量count,用来记录变量的个数
  • 规则部分: 第1个规则是找 符号开头、第 2 个符号为字母且后面为字符或数字的变量,类似于 符号开头、第2个符号为字母且后面为字符或数字的变量,类似于 符号开头、第2个符号为字母且后面为字符或数字的变量,类似于a,并计数加1. 同时,将满足条件的yytext输出;第2个规则是找数字;第3个规则是找"=" 号;第4个规则是输出"\n"; 第5个规则是忽略空格
  • 函数定义部分: 打开一个文件,然后调用yylex 函数进行词法解析,输出变量的技术,最后调用fclose关闭文件

lex 代码编译

lex a.l
gcc lex.yy.c -o test -ll

测试文件 file

$a = 1
$b = 2

执行如下命令

./test file
变量$a被赋值为数字1
变量$b被赋值为数字2
变量总数为:2

语法分析词YACC

YACC(Yet Another Compiler-Compiler) 是 UNIX/Linux 上一个用来生成编译器的编译器(编译器代码生成器). YACC使用BNF范式定义语法,能处理上下文无关文法

YACC 语法规则

YACC 语法包括3部分,即定义段、规则段和用户代码段

… 定义段 …
%%
… 规则段 …
%%
… 用户代码段 …

代码

词法分析文件: cal.l

%{
#include "y.tab.h"
#include <math.h>
%}

%%
([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) {
    yylval.dval = atof(yytext);
    return NUMBER;
}
[ \t]   ;
\n |
. return yytext[0];
%%

语法分析文件: calc.y

%{
#include <stdio.h>
#include <string.h>
#include <math.h>
int yylex(void);
void yyerror(char *);
%}

%union {
    double dval;
}
%token <dval> NUMBER
%left '-' '+'
%left '*' '/'
%nonassoc UMINUS
%type <dval> expression
%%
statement_list: statement '\n'
    | statement_list statement '\n'
    ;

statement: expression { printf("= %g\n", $1); }
    ;

expression: expression '+' expression {$$ = $1 + $3;}
    |   expression '-' expression { $$ = $1 - $3; }
    |   expression '*' expression { $$ = $1 * $3; }
    |   expression '/' expression
        {
            if ($3 == 0.0)
                yyerror("divide by zero");
            else
                $$ = $1 / $3;
        }
    |   '-' expression %prec UMINUS { $$ = -$2; }
    |   '(' expression ')' { $$ = $2; }
    |   NUMBER { $$ = $1; }
%%

void yyerror(char *str) {
    fprintf(stderr, "error:%s\n", str);
}

int yywrap() { 
    return 1;
}

int main() {
    yyparse();
}

从代码中可以看出,规则部分使用BNF范式

  • expression 最终是NUMBER,以及使用+、-、* 、/ 和 ()的组合,对加、减、乘、除、括号、负号进行表达
  • statement 是由expression 组合而成的,可以输出计算结果
  • statement 是由expression 组合而成的,可以输出计算结果
  • statement_list 是statement的组合

lex 编译

lex cal.l
  • 通过这个命令会生成lex.yy.c,里面维护了NUMBER这个Token的有穷自动机

使用 YACC对 calc.y

yacc -d calc.y
  • 会生成y.tab.c、y.tab.h

最终执行结果

gcc -o calc y.tab.c lex.yy.c
./calc
    1+2
    = 3
    3+6
    = 9

Re2C 与 Bison

词法分析器 Re2c

Re2c 是一个词法编译器,可以将符合Re2c规范的生成高效的C/C++代码,Re2c会将正则表达式生成对应的有穷状态机

代码

num.l

#include <stdio.h>
enum num_t {ERR, DEC};

static num_t lex(const char *YYCURSOR)
{
    const char *YYMARKER;
    /*!re2c
        re2c:define:YYCTYPE = char;
        re2c:yyfill:enable = 0;

        end = "\x00";
        dec = [1-9][0-9]*;

        *   {return ERR;}
        dec end {return DEC;}
    */
}

int main(int argc, char **argv)
{
    for (int i = 1; i < argc; ++i) {
        switch (lex(argv[i])) {
            case ERR: printf("error\n"); break;
            case DEC: printf("十进制表示\n"); break;
        }
    }

    return 0;
}

执行以下命令,转换成c代码

re2c num.l -o num.c

num.c

/* Generated by re2c 3.0 on Sun May 26 21:58:19 2024 */
#line 1 "num.l"
#include <stdio.h>
enum num_t {ERR, DEC};

static num_t lex(const char *YYCURSOR)
{
    const char *YYMARKER;
    
#line 11 "num.c"
{
	char yych;
	yych = *YYCURSOR;
	switch (yych) {
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy3;
		default: goto yy1;
	}
yy1:
	++YYCURSOR;
yy2:
#line 14 "num.l"
	{return ERR;}
#line 32 "num.c"
yy3:
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case 0x00: goto yy4;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy5;
		default: goto yy2;
	}
yy4:
	++YYCURSOR;
#line 15 "num.l"
	{return DEC;}
#line 53 "num.c"
yy5:
	yych = *++YYCURSOR;
	switch (yych) {
		case 0x00: goto yy4;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy5;
		default: goto yy6;
	}
yy6:
	YYCURSOR = YYMARKER;
	goto yy2;
}
#line 16 "num.l"

}

int main(int argc, char **argv)
{
    for (int i = 1; i < argc; ++i) {
        switch (lex(argv[i])) {
            case ERR: printf("error\n"); break;
            case DEC: printf("十进制表示\n"); break;
        }
    }

    return 0;
}

从上面代码中可以看出,这个状态机一共有8种状态,分别是开始状态、yy3至yy9状态,其中yy3状态是错误输出,返回ERR

yy5 状态是对应的正则匹配状态,返回DEC

在这里插入图片描述

YYCURSOR 是指向输入的指针,根据状态的流转,指针加1

语法编译器Bison

对于一条BNF文法规则,其左边是一个非终结符(symbol 或者 non-terminal),其右边则定义该非终结符是如何构成的,也称为产生式(production)

产生式可能包含非终结符,也可能包含终结符(terminal),还可能二者都有

利用BNF文来分析目标文本,比较流行的算法有LL分析(自顶向下的分析,top-down parsing),LR分析(自底向上的分析,bottom-up parsing;或者叫移进-归约分析, shift-down parsing)

其中LR算法有很多不同的变种,按照复杂度和能力递增的顺序依次是LR(0)、SLR、SLR、LALR和LR(1)

Bison是基于LALR分析法实现的,适合上下文无关文法

当Bison读入一个终结符TOKEN时,会将该终结符及其语意值一起压榨,其中这个栈叫做分析器栈(parse stack)

把一个TOKEN压入栈叫作移进。举个例子,对于计算1+2 * 3, 假设现已经读入来1 + 2 * ,那么下一个准备读入的是3,这个栈当前就有4个元素,即1、+、2和*

当已经移进的后n个终结符和组(grouping)与一个文法规则相匹配时,它们会根据该规则结合起来,这叫归约(reduction)

栈中哪些终结符和组会被单个的组(grouping)替换。同样,以1 + 2 * 3;为例,最后一个输入的字符为分号,表示结束,那么按照下面的规则进行归约:

expression '*' expression { $$ = $1 * $3 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1704601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

再见PS,Canva Create正式上线

再见&#xff0c;Photoshop&#xff01; Canva Create 正式上线&#xff0c;太疯狂了&#xff01;&#xff01; Canva是一款著名的免费在线AI图像生成器 构想你的创意&#xff0c;然后将其添加到你的设计中。使用最佳的AI图像生成器&#xff0c;观察你的文字和短语变换成美丽…

探索Java的DNA-JVM字节码深度解析

引言 在Java的世界里&#xff0c;JVM&#xff08;Java虚拟机&#xff09;是我们程序运行的心脏。而字节码&#xff0c;作为JVM的血液&#xff0c;携带着程序的执行指令。今天&#xff0c;我们将深入探索Java字节码的奥秘&#xff0c;一窥JVM如何将人类可读的代码转化为机器可执…

【香橙派AIpro】开箱测评

1.板子开箱 哟&#xff0c;看起来还不错哦&#xff01;&#xff01;&#xff01; 收货清单&#xff1a; 主板*1 1.5m数据线*1 充电头*1 1.1.充电头 近65W的充电头&#xff0c;不错不错。 1.2.主板 1.2.1.上面 哇噢&#xff0c;还送了2.4/5G的WiFi和蓝牙天线。 emm&#xf…

【NumPy】关于numpy.argsort()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

计算机专业必考之计算机指令设计格式

计算机指令设计格式 例题&#xff1a; 1.设相对寻址的转移指令占3个字节&#xff0c;第一字节为操作码&#xff0c;第二&#xff0c;第三字节为相对偏移量&#xff0c; 数据在存储器以低地址为字地址的存放方式。 每当CPU从存储器取出一个字节时候&#xff0c;自动完成&…

通过Zerossl给IP申请免费SSL证书, 实现https ip访问

参考通过Zerossl给IP申请免费SSL证书 | LogDicthttps://www.logdict.com/archives/tong-guo-zerosslgei-ipshen-qing-mian-fei-sslzheng-shu

【Linux-LCD 驱动】

Linux-LCD 驱动 ■ Framebuffer 简称 fb■ LCD 驱动程序编写■ 1、LCD 屏幕 IO 配置■ 2、LCD 屏幕参数节点信息修改■ 3、LCD 屏幕背光节点信息■ 4、使能 Linux logo 显示 ■ 设置 LCD 作为终端控制台■ 1、设置 uboot 中的 bootargs■ 2、修改/etc/inittab 文件 ■ LCD 背光…

亚马逊高效广告打法及数据优化,亚马逊高阶广告打法课

课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/89342733 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 001.1-亚马逊的广告漏斗和A9算法的升级变化.mp4 002.2-流量入口解析和广告的曝光机制.mp4 003.3-标签理论 .mp4 004.4-不同广告类…

小程序内使用路由

一:使用组件 1)创建组件 2)在需要的页面的json/app.json可实现局部使用和全局使用 在局部的话,对象内第一层,window配置也是第一层,而在全局配置也是在第一层,window在window对象内.第二层.内部执行遍历不一样. 3)页面使用 上述所写可实现在页面内使用组件.效果是页面内可以将…

预热 618,编程好书推荐——提升你的代码力

文章目录 &#x1f4cb;前言&#x1f3af;编程好书推荐&#x1f4d8; Java领域的经典之作&#x1f40d; Python学习者的宝典&#x1f310; 前端开发者的权威指南&#x1f512; 并发编程的艺术&#x1f916; JVM的深入理解&#x1f3d7; 构建自己的编程语言&#x1f9e0; 编程智…

SolidWorks教育版 学生使用的优势

在工程技术领域的学习中&#xff0c;计算机辅助设计软件&#xff08;CAD&#xff09;如SolidWorks已经成为学生掌握专业知识和技能的必要工具。SolidWorks教育版作为专为教育机构和学生设计的版本&#xff0c;不仅提供了与商业版相同的强大功能&#xff0c;还为学生带来了诸多独…

传输层安全性 (TLS)

传输层安全 (TLS) 旨在提供传输层的安全性。TLS 源自称为安全套接字层 (SSL)的安全协议。 TLS 确保任何第三方都无法窃听或篡改任何消息。 TLS 有几个好处&#xff1a; ● 加密&#xff1a; TLS/SSL 可以帮助使用加密来保护传输的数据。 ● 互操作性&#xff1a; TLS/S…

利用audacity和ffmpeg制作测试音频文件

最近要用SIPP测试一个场景&#xff0c;需要发送双声道/16K采样率/16bit量化的PCM流&#xff0c;但是下载的素材往往不能满足参数要求。那么就自己制作。 首先下载mp3文件&#xff0c;并用audacity打开。 接下来&#xff0c;点击菜单栏中轨道-重采样&#xff0c;将采样频率设为1…

备战秋招c++ 【持续更新】

T1 牛牛的快递 原题链接&#xff1a;牛牛的快递_牛客题霸_牛客网 (nowcoder.com) 题目类型&#xff1a;模拟 审题&确定思路&#xff1a; 1、超过1kg和不足1kg有两种不同收费方案 ---- 起步价问题 2、超出部分不足1kg的按1kg计算 ----- 向上取整 3、向上取整的实现思路…

运维笔记.Docker镜像分层原理

运维专题 Docker镜像原理 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/artic…

陈丽:人工智能赋能教育创新发展

5月20日&#xff0c;在顾明远先生莅临科大讯飞考察指导高端咨询会暨“人工智能与未来教育”的主题研讨会上&#xff0c;北京师范大学原副校长、中国教育技术协会副会长陈丽教授作了题为《人工智能赋能教育创新发展》的主旨报告。 &#xff08;以下内容根据陈丽教授在研讨会上的…

Python | Leetcode Python题解之第116题填充每个节点的下一个右侧节点指针

题目&#xff1a; 题解&#xff1a; class Solution:def connect(self, root: Node) -> Node:if not root:return root# 从根节点开始leftmost rootwhile leftmost.left:# 遍历这一层节点组织成的链表&#xff0c;为下一层的节点更新 next 指针head leftmostwhile head:#…

C++习题(1)

一、题目描述&#xff1a; 二、代码展示&#xff1a; #include <iostream> #include <iomanip> using namespace std; struct Student{char name[20];int id;int age;float score; }; int main() {int n;cin>>n;Student student[n];float sum0.0;for(int i0…

Ubuntu22.04之扩展并挂载4T硬盘(二百三十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

第18章-综合以上功能 基于stm32的智能小车(远程控制、避障、循迹) 基于stm32f103c8t6/HAL库/CubeMX/超详细,包含代码讲解和原理图

这个是全网最详细的STM32项目教学视频。 第一篇在这里: 视频在这里 STM32智能小车V3-STM32入门教程-openmv与STM32循迹小车-stm32f103c8t6-电赛 嵌入式学习 PID控制算法 编码器电机 跟随 第18章-综合以上功能 18-按键和app按钮切换功能 根据上面介绍&#xff0c;我们的模式可…