【编译原理】实验二 递归下降分析程序设计(C语言、Python、Flex&Bison实现)

一、实验目的

通过设计、编制、调试一个递归下降语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,掌握常用的语法分析方法。通过本实验,应达到以下目标:  

(1) 掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。

(2) 掌握语法分析的实现方法。

(3) 上机调试编出的语法分析程序。

二、实验内容与设计思想

完成以下描述算术表达式的LL(1)文法的递归下降分析程序构造

G[E]:

         E  → TE′

         E′→ +TE′|ε

         T  → FT′

         T′→ *FT′|ε

F  → (E) | i

    说明:终结符号i为用户定义的简单变量,即标识符的定义。

要求具有如下功能:

  1)从文件读入算术表达式/或者从终端输入

2)总控函数分析算术表达式;

3)根据分析结果正误,分别给出不同信息

三、源代码

1、C语言

lab2.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
char str[30];       //字符串数组
int subscript = 0;  //str数组的下标
int len;            //数组长度
int tnum;           //测试次数
FILE *fp = NULL;    //声明文件
//1、处理非终结符E的子程序
void processE();
//2、处理非终结符E_e(即E')的子程序,e即英文extend
void processE_e();
//3、处理非终结符T的子程序
void processT();
//4、处理非终结符T_e的子程序
void processT_e();
//5、处理非终结符F的子程序
void processF();
//6、从文件读入算术表达式
void readFromFile(FILE *fp);
//7、从终端输入算数表达式
void enterFromTerminal();

lab2.c

#include "lab2.h"
//1、处理非终结符E的子程序,E->TE'
void processE(){
    processT();
    processE_e();
}
//2、处理非终结符E_e(即E')的子程序,E'->+TE'|ε  
void processE_e(){
    if(str[subscript] == '+'){
        subscript ++;
        processT();
        processE_e();
    }  
}
//3、处理非终结符T的子程序,T->FT'
void processT(){
    processF();
    processT_e();
}
//4、处理非终结符T_e的子程序,T'->*FT'|ε
void processT_e(){
    if(str[subscript] == '*'){
        subscript ++;
        processF();
        processT_e();
    } 
}
//5、处理非终结符F的子程序,F->(E)|i
void processF(){
    if(str[subscript] == 'i')
        subscript ++;
        //printf("Successfully!\n");
    else if(str[subscript] == '('){
        subscript ++;
        processE();
        if(str[subscript] == ')')
            subscript ++;
        else{
            printf("The string is illegal.Error!");
            exit(0);
        }
    }
    else{
        printf("The string is illegal.Error!");
        exit(0);
    }
}
//6、从文件读入算术表达式
void readFromFile(FILE *fp){
    while(fgets(str, 100, fp) != NULL){
        printf("Read line = %s",str);
        processE();
        printf("Analyze successfully!\n");
        subscript = 0;     //下标继续从0开始
    }
    printf("—————End of reading file—————\n");
}
//7、从终端输入算数表达式
void enterFromTerminal(){
    printf("Please enter the number of strings you want to parse:");
    scanf("%d",&tnum);
    while(tnum--){
        printf("Please enter a string:\n");
        scanf("%s",str);
        len = strlen(str);
        //printf("%d",len);
        //str[len+1] = '\0';
        processE();
        printf("Analyze successfully!\n");
        //strcpy(str,"");    //清空数组,为下一次字符串输入腾出空间
        subscript = 0;     //下标继续从0开始
    }
}
//总控函数
int main(){
    int choice;
    while(1){
        printf("--------------------------------------------------------------------------------------\n");
        printf("1、Enter from terminal\n");
        printf("2、Read from file\n");
        printf("Please choose (1 or 2) which method you want to analyze arithmetic expressions:\n");
        printf("(Note:Press 0 to exit)\n");
        scanf("%d",&choice);
        switch(choice){
        case 1:
            enterFromTerminal();
            printf("\n");
            break;
        case 2:
            fp = fopen("test.txt", "r");
            if (!fp)
                printf("The file doesn't exist\n");
            else 
                readFromFile(fp);
            fclose(fp);
            printf("\n");
            break;
        case 0:
            // system("cls");
            printf("Exited!\n");
            exit(0);
            break;
        }
    }
    return 0;
}

2、Python

lab2.py

# 全局变量
subscript = 0  # str数组下标
str = ""       # 字符串
# 1、处理非终结符E的子程序,E->TE'
def processE():  
    processT()
    processE_e()
# 2、处理非终结符E_e(即E')的子程序,E'->+TE'|ε 
def processE_e(): 
    global subscript
    global str
    if str[subscript] == '+':
        subscript  = subscript + 1
        processT()
        processE_e()
# 3、处理非终结符T的子程序,T->FT'
def processT():
    processF()
    processT_e()
# 4、处理非终结符T_e的子程序,T'->*FT'|ε
def processT_e():
    global subscript
    global str
    if str[subscript] == '*':
        subscript = subscript + 1
        processF()
        processT_e()
# 5、处理非终结符F的子程序,F->(E)|i
def processF():
    global subscript
    global str
    if str[subscript] == 'i':
        subscript = subscript + 1
    elif str[subscript] == '(':
        subscript = subscript + 1
        processE()
        if str[subscript] == ')':
            subscript = subscript + 1
        else:
            print(str)
            print("The string is illegal.Error!")
            return 
    else:
        print(str)
        print("The string is illegal.Error!")
        return
# 6、从文件读入算术表达式
def readFromFile():
    global subscript
    global str
    # Open file        
    fileHandler  =  open  ("test.txt",  "r")
    while  True:
        # Get next line from file
        line  =  fileHandler.readline()
        # If line is empty then end of file reached
        if  not  line  :
            break
        str = line.strip()
        print("Read line = ",str)
        str += '#'
        processE()
        print("Analyze successfully!")
        subscript = 0; 
    # Close Close    
    fileHandler.close()
    print("—————End of reading file—————")
# 7、从终端输入算数表达式
def enterFromTerminal():
    global str
    tnum = input("Please enter the number of strings you want to parse:")
    tnum = int(tnum)
    while tnum > 0:
        str = input("Please enter a string(end with '#'):")
        processE()
        print("Analyze suinputccessfully!")
        str = ""
        subscript = 0     # 下标继续从0开始
        tnum = tnum - 1
# 总控函数
if __name__ == '__main__':
    while True:
        print("1、Enter from terminal")
        print("2、Read from file")
        print("Please choose (1 or 2) which method you want to analyze arithmetic expressions:")
        print("(Note:Press any key to exit)")
        ch = input()
        if ch == '1':
            enterFromTerminal()
        elif ch == '2':
            readFromFile()
        else:
            print("Exited!")
            break

3、Flex&Bison

lab2ll.l

%{
#include <stdlib.h>
int yyerror(char *str);
#include "lab2yy.tab.h"
%}
%%
[ \t]*  {}
[0-9]+  {
            yylval = atoi(yytext);
            return DIGIT;
        }
[*+\n]      return *yytext;
.           {yyerror("The string is illegal.Error!");}
%%
int yyerror(char *str){
    fprintf(stderr,"%s\n",str);
    return 1;      
}
int yywrap(){
    return 1;
}

lab2yy.y

{
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int yylex();
int yyerror(char *str);
%}
%token DIGIT
%%
line   : expr              {printf("%d\n",$1);}
       ;
expr   : expr '+' term     {$$ = $1 + $3;}
       | term       
       ;
term   : term '*' factor    {$$ = $1 * $3;}
       | factor
       ;
factor : '(' expr ')'       {$$ = $2;}
       | DIGIT
       ;
%%
int main() {
    printf("-----------Parser----------------\n");
    yyparse();
    return 0;
}
/*
终端编译flex&yacc文件命令如下:
bison -vdty lab2yy.y
此时会产生三个文件,即y.tab.h, y.tab.c, y.output
或 bison -d lab2yy.y
此时会产生两个文件,即lab2yy.tab.h lab2yy.tab.c
flex lab2ll.l            
此时会产生一个文件,即lex.yy.c
gcc -o lab2yy y.tab.c lex.yy.c
或 gcc -o lab2yy lab2yy.tab.c lex.yy.c(第二个bison命令时)
.\lab2yy
*/

四、参考博客

(1条消息) 递归下降语法分析程序设计_poclist的博客-CSDN博客icon-default.png?t=M85Bhttps://blog.csdn.net/bfboys/article/details/52530550(1条消息) 【编译原理】【C语言】实验三:递归下降分析法_zoxiii的博客-CSDN博客_递归下降分析icon-default.png?t=M85Bhttps://blog.csdn.net/qq_41315788/article/details/122455432第13章 用 bison 做语法分析 — 自己动手写编译器 (pandolia.net)icon-default.png?t=M85Bhttps://pandolia.net/tinyc/ch13_bison.html编译工程附录:Bison基础 – 知乎 (zhihu.com)icon-default.png?t=M85Bhttps://zhuanlan.zhihu.com/p/111445997#:~:text=%24%E5%B0%B1%E6%98%AFbison%E4%B8%AD%E6%AF%8F%E4%B8%AA%E4%BA%A7%E7%94%9F%E5%BC%8F%E4%B8%AD%E5%90%84%E9%A1%B9%E7%9A%84%E5%80%BC%EF%BC%9B%24%24%E4%BA%A7%E7%94%9F%E5%BC%8F%E5%B7%A6%E9%83%A8%EF%BC%9B%241%E6%98%AF%E4%BA%A7%E7%94%9F%E5%BC%8F%E5%8F%B3%E8%BE%B9%E7%AC%AC1%E4%B8%AA%E7%AC%A6%E5%8F%B7%E7%BB%91%E5%AE%9A%E7%9A%84%E5%80%BC%EF%BC%8C%242%E6%98%AF%E7%AC%AC2%E4%B8%AA%E7%AC%A6%E5%8F%B7%EF%BC%8C%243%E6%98%AF%E7%AC%AC3%E4%B8%AA%E7%AC%A6%E5%8F%B7%EF%BC%8C%E4%BB%A5%E6%AD%A4%E7%B1%BB%E6%8E%A8%E3%80%82,%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E6%98%BE%E5%BC%8F%E6%8C%87%E5%AE%9A%E5%A4%84%E7%90%86%E8%AF%AD%E5%8F%A5%EF%BC%8Cbison%E9%BB%98%E8%AE%A4%E6%83%85%E5%86%B5%E4%B8%8B%E6%8A%8A%241%E7%9A%84%E5%80%BC%E6%8B%B7%E8%B4%9D%E7%BB%99%24%24%E3%80%82———————————————————————————————————————————

不足之处欢迎指正~

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2023年11月22日
下一篇 2023年11月22日

相关推荐