贵州大学-编译原理实验2-句法分析器

考虑下面的C语言子集的文法,其中<>括起来的为非终结符,粗体为终结符。

® <statement_list>

<statement_list> ®

​ | <statement_list>

® <compound_statement>

| <expression_statement>

​ | <selection_statement>

​ | <iteration_statement>

<compound_statement> ® { }

​ | { <statement_list> }

<expression_statement> ® ;

​ | ;

® <assignment_expression>

​ | , <assignment_expression>

<assignment_expression> ® <equality_expression>

​ | ID = <assignment_expression>

<equality_expression> ® <relational_expression>

​ | <equality_expression> == <relational_expression>

​ | <equality_expression> != <relational_expression>

<relational_expression> ® <additive_expression>

​ | <relational_expression> < <additive_expression>

​ | <relational_expression> > <additive_expression>

​ | <relational_expression> <= <additive_expression>

​ | <relational_expression> >= <additive_expression>

<additive_expression> ® <multiplicative_expression>

​ | <additive_expression> + <multiplicative_expression>

​ | <additive_expression> - <multiplicative_expression>

<multiplicative_expression> ® <primary_expression>

​ | <multiplicative_expression> ***** <primary_expression>

​ | <multiplicative_expression> / <primary_expression>

<primary_expression> ® ID | NUM | STRING | ( )

<selection_statement> ® IF ( )

<iteration_statement> ® WHILE ( )

​ | DO WHILE ( ) ;

要求:对给定的C语言程序进行句法分析,输出得到的分析树。

例如,下面的源程序代码

​ sum = 0.0;

​ x = 1.0;

​ while (x <= 100) sum = sum + x;

句法分析结果为

|-- <statement_list>

|-- <statement_list>

| |-- <statement_list>

| | |--

| | |-- <expression_statement>

| | |--

| | | |-- <assignment_expression>

| | | |-- ID

| | | |-- =

| | | |-- <assignment_expression>

| | | |-- <equality_expression>

| | | |-- <relational_expression>

| | | |-- <additive_expression>

| | | |-- <multiplicative_expression>

| | | |-- <primary_expression>

| | | |-- NUM

| | |-- ;

| |--

| |-- <expression_statement>

| |--

| | |-- <assignment_expression>

| | |-- ID

| | |-- =

| | |-- <assignment_expression>

| | |-- <equality_expression>

| | |-- <relational_expression>

| | |-- <additive_expression>

| | |-- <multiplicative_expression>

| | |-- <primary_expression>

| | |-- NUM

| |-- ;

|--

​ |-- <iteration_statement>

​ |-- WHILE

​ |-- (

​ |--

​ | |-- <assignment_expression>

​ | |-- <equality_expression>

​ | |-- <relational_expression>

​ | |-- <relational_expression>

​ | | |-- <additive_expression>

​ | | |-- <multiplicative_expression>

​ | | |-- <primary_expression>

​ | | |-- ID

​ | |-- <=

​ | |-- <additive_expression>

​ | |-- <multiplicative_expression>

​ | |-- <primary_expression>

​ | |-- NUM

​ |-- )

​ |--

​ |-- <expression_statement>

​ |--

​ | |-- <assignment_expression>

​ | |-- ID

​ | |-- =

​ | |-- <assignment_expression>

​ | |-- <equality_expression>

​ | |-- <relational_expression>

​ | |-- <additive_expression>

​ | |-- <additive_expression>

​ | | |-- <multiplicative_expression>

​ | | |-- <primary_expression>

​ | | |-- ID

​ | |-- +

​ | |-- <multiplicative_expression>

​ | |-- <primary_expression>

​ | |-- ID

​ |-- ;

讲道理,编译原理以后应该变成选修课了,不会还有人选这个课吧

qj 检查实验问的是真细 啊。(我错了,我们秦老师还是挺听劝的,爱了爱了)行,废话不多说,进入正题。


这是编译器编译的基本步骤,本次实验的目标是要构建出一个语法分析树,
所以也需要用到词法分析的内容。
词法分析产生的记号流 ----> 语法分析
当然语法分析可使用的工具挺多,比如最早出现的yacc ,现在很流行的antlr 等。
不像词法分析器,用了lex 之后几乎都不怎么需要写代码,尽管我们使用了自动生成语法的工具,仍然需要写一定代码。 所以现在很多语言其实都是自己写代码来实现语法分析,我也尝试过,写LL(1) ,恶心死我了,还是用工具吧。

首先要安装我们需要的工具

链接:https://pan.baidu.com/s/1-M-Mqgg9HezGnhHRZzu6pQ?pwd=cpa1
提取码:cpa1

下载后解压

大家应该知道啥是环境变量吧,要在命令行 cmd 中运行这些程序,我们需要将其路径添加到Path 中。

配置好后

flex -V  //注意是大写的V
bison -V    //同大写的V
gcc -v      //注意是小写的v

看这几个是否有正确输出

接着大家自学一下基本的yacc 和flex 语法吧

https://blog.csdn.net/weixin_44007632/article/details/108666375

可以参考这个文档,讲的非常详细。

我来稍微说一下思路吧


其中的yylex 函数就是词法分析器产生的,下面有个 pro.l 文件,编译的时候会联合编译。
如果没有 用lex,你自己写了yylex 函数也是可以滴,网上有点参考应该挺多

之后一部分就是文法定义了,
yacc 是自底向上的,所以当匹配到

命名为 pro.y %{
#include <stdio.h>
#include <stdlib.h> //malloc函数
#include <string.h>
#include <stdbool.h> // 引入 布尔类型
int yylex(void);
void yyerror(char *);
extern FILE * yyin;  //声明yyin,yyout 变量,定义在后面
extern FILE * yyout;//多叉树定义
struct TNode{char *label;struct TNode *bro;struct TNode *son;
};typedef struct TNode *Tree;Tree CreateTree(char *label) //创建一个label为传入参数的树节点
{Tree T = (Tree)malloc(sizeof(struct TNode));if (T != NULL) {T->bro = NULL;T->son = NULL;T->label = malloc(strlen(label) + 1);  // +1 用于存储字符串结尾的'\0'if (T->label != NULL) {strcpy(T->label, label);} }return T;
}void addSon(Tree father,Tree son) //前向插入son链表 先来的是右儿子
{son->bro = father->son;father->son = son;return;
}//栈定义struct SNode{Tree *Data;int Top;int MaxSize;
};typedef struct SNode *Stack;Stack CreateStack( int MaxSize ) //创建一个长度为MaxSize的栈
{Stack S = (Stack)malloc(sizeof(struct SNode));S->Data = (Tree *)malloc(MaxSize * sizeof(Tree));S->Top = -1;S->MaxSize = MaxSize;return S;
}bool IsFull( Stack S )
{return (S->Top == S->MaxSize-1);
}bool push( Stack S, Tree X )
{if ( IsFull(S) ) {printf("堆栈满");return false;}else {S->Data[++(S->Top)] = X;return true;}
}bool IsEmpty( Stack S )
{return (S->Top == -1);
}Tree pop( Stack S )
{if ( IsEmpty(S) ) {printf("堆栈空");return NULL;}else return ( S->Data[(S->Top)--] );
}char indent[100]; void addIndent(int m)
{if(m == 3){  //没有兄弟节点的情况strcat(indent,"   ");}else{       //有兄弟节点的情况strcat(indent,"|   ");}
}void subIndent(int m)
{int l = strlen(indent);if(m == 3){l -= 3;}else{l -= 4;}indent[l] = '\0';
}void disp(Tree T)
{if(strcmp(T->label, "<program>") == 0){printf("%s\n",T->label);addIndent(3);disp(T->son);}do{printf("%s|-- %s\n",indent,T->label);if(T->son != NULL){if(T->bro != NULL)addIndent(4);elseaddIndent(3);disp(T->son);if(T->bro != NULL)subIndent(4);elsesubIndent(3);}T = T->bro;}while(T != NULL);
}Stack S = NULL;
Tree current = NULL;%}%token BREAK CHAR DO DOUBLE ELSE IF INT RETURN VOID WHILE ID NUM STRING ADD SUB MUL DIV GT GE LT LE EQ NE ASSIGN LB RB LR RR COMMA SEMI ERROR%%program                     : statement_list              {current = CreateTree("<program>");addSon(current,pop(S));push(S,current);};statement_list              : statement                    {current = CreateTree("<statement_list>");addSon(current,pop(S));push(S,current);}| statement_list statement       {current = CreateTree("<statement_list>");addSon(current,pop(S));addSon(current,pop(S));push(S,current);};statement                   : compound_statement            {current = CreateTree("<statement>");addSon(current,pop(S));push(S,current);}| expression_statement          {current = CreateTree("<statement>");addSon(current,pop(S));push(S,current);}| selection_statement           {current = CreateTree("<statement>");addSon(current,pop(S));push(S,current);}| iteration_statement           {current = CreateTree("<statement>");addSon(current,pop(S));push(S,current);};compound_statement          : LB RB                         {current = CreateTree("<compound_statement>");addSon(current,CreateTree(")"));addSon(current,CreateTree("("));push(S,current);}| LB statement_list RB          {current = CreateTree("<compound_statement>");addSon(current,CreateTree(")"));addSon(current,pop(S));addSon(current,CreateTree("("));push(S,current);};expression_statement        : SEMI                          {current = CreateTree("<expression_statement>");addSon(current,CreateTree(";"));push(S,current);}| expression SEMI               {current = CreateTree("<expression_statement>");addSon(current,CreateTree(";"));addSon(current,pop(S));push(S,current);};expression                  : assignment_expression         {current = CreateTree("<expression>");addSon(current,pop(S));push(S,current);}| expression COMMA assignment_expression    {current = CreateTree("<expression>");addSon(current,pop(S));addSon(current,CreateTree(","));addSon(current,pop(S));push(S,current);};assignment_expression       : equality_expression           {current = CreateTree("<assignment_expression>");addSon(current,pop(S));push(S,current);}| ID ASSIGN assignment_expression   {current = CreateTree("<assignment_expression>");addSon(current,pop(S));addSon(current,CreateTree("="));addSon(current,CreateTree("ID"));push(S,current);};equality_expression         : relational_expression         {current = CreateTree("<equality_expression>");addSon(current,pop(S));push(S,current);}| equality_expression EQ relational_expression  {current = CreateTree("<equality_expression>");addSon(current,pop(S));addSon(current,CreateTree("=="));addSon(current,pop(S));push(S,current);}| equality_expression NE relational_expression  {current = CreateTree("<equality_expression>");addSon(current,pop(S));addSon(current,CreateTree("!="));addSon(current,pop(S));push(S,current);};relational_expression       : additive_expression           {current = CreateTree("<relational_expression>");addSon(current,pop(S));push(S,current);}| relational_expression LT additive_expression  {current = CreateTree("<relational_expression>");addSon(current,pop(S));addSon(current,CreateTree("<"));addSon(current,pop(S));push(S,current);}| relational_expression GT additive_expression  {current = CreateTree("<relational_expression>");addSon(current,pop(S));addSon(current,CreateTree(">"));addSon(current,pop(S));push(S,current);}| relational_expression LE additive_expression  {current = CreateTree("<relational_expression>");addSon(current,pop(S));addSon(current,CreateTree("<="));addSon(current,pop(S));push(S,current);}| relational_expression GE additive_expression  {current = CreateTree("<relational_expression>");addSon(current,pop(S));addSon(current,CreateTree(">="));addSon(current,pop(S));push(S,current);};additive_expression         : multiplicative_expression     {current = CreateTree("<additive_expression>");addSon(current,pop(S));push(S,current);}| additive_expression ADD multiplicative_expression {current = CreateTree("<additive_expression>");addSon(current,pop(S));addSon(current,CreateTree("+"));addSon(current,pop(S));push(S,current);}| additive_expression SUB multiplicative_expression {current = CreateTree("<additive_expression>");addSon(current,pop(S));addSon(current,CreateTree("-"));addSon(current,pop(S));push(S,current);};multiplicative_expression   : primary_expression            {current = CreateTree("<multiplicative_expression>");addSon(current,pop(S));push(S,current);}| multiplicative_expression MUL primary_expression  {current = CreateTree("<multiplicative_expression>");addSon(current,pop(S));addSon(current,CreateTree("*"));addSon(current,pop(S));push(S,current);}| multiplicative_expression DIV primary_expression  {current = CreateTree("<multiplicative_expression>");addSon(current,pop(S));addSon(current,CreateTree("/"));addSon(current,pop(S));push(S,current);};primary_expression          : ID                            {current = CreateTree("<primary_expression>");addSon(current,CreateTree("ID"));push(S,current);}| NUM                           {current = CreateTree("<primary_expression>");addSon(current,CreateTree("NUM"));push(S,current);}| STRING                        {current = CreateTree("<primary_expression>");addSon(current,CreateTree("STRING"));push(S,current);}| LR expression RR              {current = CreateTree("<primary_expression>");addSon(current,CreateTree(")"));addSon(current,pop(S));addSon(current,CreateTree("("));push(S,current);};selection_statement         : IF LR expression RR statement {current = CreateTree("<selection_statement>");addSon(current,pop(S));addSon(current,CreateTree(")"));addSon(current,pop(S));addSon(current,CreateTree("("));addSon(current,CreateTree("IF"));push(S,current);};iteration_statement         : WHILE LR expression RR statement              {current = CreateTree("<iteration_statement>");addSon(current,pop(S));addSon(current,CreateTree(")"));addSon(current,pop(S));addSon(current,CreateTree("("));addSon(current,CreateTree("WHILE"));push(S,current);}| DO statement WHILE LR expression RR SEMI      {addSon(current,CreateTree(";"));addSon(current,CreateTree(")"));addSon(current,pop(S));addSon(current,CreateTree("("));addSon(current,CreateTree("WHILE"));addSon(current,pop(S));addSon(current,CreateTree("DO"));push(S,current);};%%
void yyerror(char *str){fprintf(stderr,"error:%s\n",str);
}int yywrap(){return 1;
}int main(int argc, char **argv)
{if (argc>1){FILE *file;file=fopen(argv[1],"r");if(file)yyin=file;}if (argc>2){FILE *file;file=fopen(argv[2],"w");if(file){yyout=file;}}S = CreateStack(65535);yyparse();current = pop(S);disp(current);return 0;
}

命名为 pro.l%{
#include<stdio.h>
#include "y.tab.h"
void yyerror(char *);
void yywrap();
%}DIGIT       [0-9]
LETTER      [a-zA-Z_]
HEX         [a-fA-F0-9]
EX          [Ee][+-]?{DIGIT}+
FS          (f|F|l|L)
IS          (u|U|l|L)*
XID          {LETTER}({LETTER}|{DIGIT})*XNUM         0[xX]{HEX}+{IS}?|0{DIGIT}+{IS}?|{DIGIT}+{IS}?|L?'(\\.|[^\\'])+'|{DIGIT}+{EX}{FS}?|{DIGIT}*"."{DIGIT}+({EX})?{FS}?|{DIGIT}+"."{DIGIT}*({EX})?{FS}?XSTRING      L?\"(\\.|[^\\"])*\"COMMENT     "/*"([^\*]|(\*)*[^\*/])*(\*)*"*/" %%
{COMMENT}    {}
break        {return BREAK;}
char         {return CHAR;}
do           {return DO;}
double       {return DOUBLE;}
else         {return ELSE;}
if           {return IF;}
int          {return INT;}
return       {return RETURN;}
void         {return VOID;}
while        {return WHILE;}
"+"          {return ADD;}
"–"          {return SUB;}
"*"          {return MUL;}
"/"          {return DIV;}
">"          {return GT;}
">="         {return GE;}
"<"          {return LT;}
"<="         {return LE;}
"=="         {return EQ;}
"!="         {return NE;}
"="          {return ASSIGN;}
"{"          {return LB;}
"}"          {return RB;}
"("          {return LR;}
")"          {return RR;}
","          {return COMMA;}
";"          {return SEMI;}{XID}        {return ID;}
{XNUM}       {return NUM;}
{XSTRING}    {return STRING;}\n           {}
[ \t]+       {}
.            {return ERROR;}%%

每次编译这两玩意,非常麻烦
可以简单写个脚本

命名为 test.bat
@echo off
set str=%1
@echo on
bison --yacc -dv %str%.y
flex %str%.l
gcc -o %str% y.tab.c lex.yy.c

在cmd 中打开,
输入test.bat pro 就会自动帮你编译

最后我们执行 .exe 文件就行了,就得到了分析树

开头第一句报错是因为老师给的文法没有 else 。没得事的

贵州大学-编译原理实验2-句法分析器相关推荐

  1. 编译原理实验-LL1语法分析器(自动生成First集、Follow集求法)java实现

    编译原理实验-LL1语法分析器(自动生成First.Follow)java 博主在做实验时,参考众多他人代码,发现bug众多,在@moni_mm代码基础上,与伙伴把能看到的BUG都做出修正,同时增添了 ...

  2. 编译原理 实验2 语法分析器的构造

    [实验目的] 练习构造语法分析程序的方法,熟悉上下文无关文法的使用,加深对课堂教学的理解:提高词法分析方法的实践能力 [实验要求] 利用某一高级程序设计语言构造语法分析程序 [具体要求]对于给定的文法 ...

  3. 编译原理实验:自上而下语法分析

    编译原理实验:自上而下语法分析 1. 实验题目:自上而下语法分析 实验目的 实验内容 实验要求 输入输出 2. 设计思想 3. 算法流程 4. 源程序 5. 调试数据 1. 实验题目:自上而下语法分析 ...

  4. 【编译原理】LR语法分析器的设计与实现

    LR语法分析器的设计与实现 本文为当时编译原理实验作业,要求用设计的思想完成,小题大做,仅供参考 文章目录 LR语法分析器的设计与实现 实验要求 实现功能 输入输出 样例 一.LR语法分析器问题定义 ...

  5. 编译原理实验三 语义分析程序设计与实现

    一.实验目的 在实现词法.语法分析程序的基础上,编写相应的语义子程序,进行语义处理,加深对语法制导翻译原理的理解,进一步掌握将语法分析所识别的语法范畴变换为某种中间代码(四元式)的语义分析方法,并完成 ...

  6. 编译原理实验二:Bison

    编译原理实验二:Bison 实验要求 1.了解Bision基础知识,如何将文法产生式转换为Bison语句 2.阅读/src/common/SyntaxTree.c,对应头文件 /include/Syn ...

  7. 编译原理实验:自下而上语法分析

    编译原理实验:自下而上语法分析 1. 实验题目:自下而上语法分析 实验目的 实验内容 实验要求 输入输出 2. 设计思想 3. 算法流程 4. 源程序 5. 调试数据 1. 实验题目:自下而上语法分析 ...

  8. 编译原理实验二(全部存储到数组再逐行验证语法版.....这种思路被老师否了,应该是验证一行扔掉一行才对)

    编译原理实验二(可能还有BUG,不确定继续找) 要大改一次23333,老师的意思是不能用数组存储,而是一边识别单词,然后识别完一行就判断一次语法 写实验二的时候找到的实验一的一个逻辑错误 改动了实验一 ...

  9. 编译原理实验c语言cfg文法,编译原理

    地址在符号表中引入指针previous,来连接上一个符号的首地址运行时存储空间组织活动记录用于管理函数变量的信息栈式存储过程进入和返回通过变更top和sp指针,实现活动记录的栈式处理静态链实现局部变量 ...

最新文章

  1. 自动化运维工具之puppet简单实用
  2. 进程间通信的方式(四):信号量
  3. 变形版汉诺塔:LeetCode:70爬楼梯
  4. IE 中释放javascript对象
  5. abb机器人指令手册_第1519课 ABB机器人初级教程
  6. android代码旋转屏幕,Android Activity源码分析--windowmanager屏幕旋转研究
  7. c标签判断true false jsp_北京尚学堂卓越班252天[第042天]——Jsp
  8. 前端那些事之Nuxt.js
  9. python_字符串常用方法
  10. Python(字符编码)
  11. mtk驱动sensor移植
  12. window10 修改jdk版本,从jdk10降到jdk1.8,java -version版本没有变化的问题解决
  13. 城市场景车路协同网络该怎么建?
  14. VS解决方案下文件的含义(记录)
  15. Key Reinstallation Attacks: Forcing Nonce Reuse in WPA2
  16. 小程序源码:AI微信小程序源码下载人脸照片AI转换动漫照片全新源码安装简单无需服务器域名-多玩法安装简单
  17. 微信商户号25位招商银行号
  18. 《Spring事务传播行为详解》经典例子 看完这篇,别的不用看了
  19. bug---springboot报错Consider the following: If you want an embedded database (H2, HSQL
  20. 轻量化网络:ShuffleNet v2解析

热门文章

  1. pe制作linux硬盘的镜像文件_制作winPE、Linux、maxdos三合一U盘启动盘
  2. 微信小程序 wxapkg 反编译 获得微信小游戏跳一跳源码
  3. Java实现 LeetCode 622 设计循环队列(暴力大法)
  4. ASP.NET入门教程(五)发表文章
  5. python:实现将照片右上角加上红色的数字(附完整源码)
  6. 菜鸟网络营销赚钱指南
  7. 安信可分享 | 分享一个基于airkiss协议的配网小程序,实现小程序一键配网安信可ESP32C3\ESP8266\ESP32\ESP32S2系列的模组。(附带源码)
  8. android 传输视频文件,如何将音视频文件传输到安卓设备中
  9. Flutter 电影 app 应用,兼容 Android 和 iOS,使用豆瓣开放Api。
  10. 名帖138 梁诗正 小楷《奏报浙省雨水田禾粮价情形折》