zoukankan      html  css  js  c++  java
  • 软件构造——SLR(1)语法分析

    实验目的

    构造LR分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。

    实验内容

    对下列文法,用SLR(1)分析法对任意输入的符号串进行分析:


    (1)S->E

    (2)E->E+T

    (3)E->T

    (4)T->T*F

    (5)T->F

    (6)F->(E)

    (7)F->i

    设计思想

    (1)总控程序,也可以称为驱动程序。对所有的LR分析器总控程序都是相同的。

    (2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。

    (3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。

    分析器的动作就是由栈顶状态和当前输入符号所决定。

    u  LR分析器由三个部分组成:

    u  其中:SP为栈指针,S[i]为状态栈,X[i]为文法符号栈。状态转换表用GOTO[i,X]=j表示,规定当栈顶状态为i,遇到当前文法符号为X时应转向状态j,X为终结符或非终结符。

    u  ACTION[i,a]规定了栈顶状态为i时遇到输入符号a应执行。动作有四种可能:

    (1)移进:

        action[i,a]= Sj:状态j移入到状态栈,把a移入到文法符号栈,其中i,j表示状态号。

    (2)归约:

        action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A- B的产生式,若B的长度为R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉R个符号,即栈指针SP减去R,并把A移入文法符号栈内,j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。

    (3)接受acc:

        当归约到文法符号栈中只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。

    (4)报错:

    当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入端不是该文法能接受的符号串。

    【实验要求】

    1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。

    2、如果遇到错误的表达式,应输出错误提示信息。

    3、程序输入/输出实例:

    输入一以#结束的符号串(包括+—*/()i#):在此位置输入符号串

    输出过程如下:

    步骤     状态栈     符号栈      剩余输入串            动 作 

     1          0             #          i+i*i#               移进 

    【实验结果】

    代码:

      1 Main.cpp
      2 #include<iostream>
      3 #include<stack>
      4 #include<string>
      5 #include <stdlib.h>
      6 using namespace std;
      7 string action[12][6] = { "S5", "0", "0", "S4", "0", "0",
      8 //ACTION 表
      9 "0", "S6", "0", "0", "0", "acc",
     10 "0", "r2", "S7", "0", "r2", "r2",
     11 "0", "r4", "r4", "0", "r4", "r4",
     12 "S5", "0", "0", "S4", "0", "0",
     13 "0", "r6", "r6", "0", "r6", "r6",
     14 "S5", "0", "0", "S4", "0", "0",
     15 "S5", "0", "0", "S4", "0", "0",
     16 "0", "S6", "0", "0", "S11", "0",
     17 "0", "r1", "S7", "0", "r1", "r1",
     18 "0", "r3", "r3", "0", "r3", "r3",
     19 "0", "r5", "r5", "0", "r5", "r5" };
     20 int gotoarr[12][3] = { 1, 2, 3, //GOTO 表
     21 0, 0, 0,
     22 0, 0, 0,
     23 0, 0, 0,
     24 8, 2, 3,
     25 0, 0, 0,
     26 0, 9, 3,
     27 0, 0, 10,
     28 0, 0, 0,
     29 0, 0, 0,
     30 0, 0, 0,
     31 0, 0, 0 };
     32 char vt[6] = { 'i', '+', '*', '(', ')', '#' }; //存放终结符
     33 char vn[3] = { 'E', 'T', 'F' }; //存放非终结符
     34 string Production[6] = { "E->E+T", "E->T", "T->T*F", "T->F", "F->(E)", "F->i" };//产生式集合
     35 //int com= 0;//记录当前进行处理的输入字符串字符位置
     36 int com = 0;
     37 int line = 1;//记录处理的步骤数
     38 bool flag = false;
     39 int StatusNumber = 1;//栈中状态数
     40 string stacktd = "#";//记录符号栈中内容
     41 int Status[50] = { 0 };//记录状态栈
     42 stack <char> Stack;//创建一个符号栈
     43 stack <int> status;//创建一个状态栈
     44 void Judge(int &i, int j, char arr[], char ch, string s){//判断输入串是否由文法终结符组成
     45     flag = false;
     46     for (int l = 0; l<j; l++){
     47         if (ch == arr[l]){
     48             flag = true;
     49             i = l;
     50             break;
     51         }
     52     }
     53     if (flag == false){
     54         cout << "	Error" << endl;
     55         //com = s.size();
     56         com = s.size();
     57     }
     58 }
     59 void Outputstatus(){//输出状态集
     60     for (int i = 0; i<StatusNumber; i++)
     61         cout << Status[i];
     62 }
     63 void Outputstring(string s){//输出未处理的字符串
     64     for (int i = com; i<s.size(); i++)
     65         cout << s.at(i);
     66 }
     67 void Output(string s){//输出步骤、 状态集、 符号集、 输入串
     68     cout << line << "	";
     69     Outputstatus();
     70     cout << "	" << stacktd << "	";
     71     Outputstring(s);
     72     cout << "		";
     73     line++;
     74 }
     75 void Shift(int i, string s){//移进函数 S
     76     Output(s);
     77     cout << "ACTION[" << status.top() << "," << s.at(com) << "]=S" << i << ",状态" << i << "入栈" << endl;
     78     status.push(i);//将状态 i 压进状态
     79     Status[StatusNumber] = i;//Status 记录状态栈的内容
     80     Stack.push(s.at(com));//将当前面临的输入串符号压进符号栈
     81     stacktd = stacktd + s.at(com);//stacktd 记录符号栈的内容
     82     com++;//当前面临的输入串字符往后移一位
     83     StatusNumber++;//状态数加一
     84 }
     85 void Goto(stack <int> st1, stack <char> st2, string s){//GoTo 语句
     86     int j = -1;
     87     int ch1 = st1.top();
     88     char ch2 = st2.top();
     89     Judge(j, 3, vn, ch2, s);//求得 ch2 在非终结符表中的位置
     90     if (gotoarr[ch1][j] == 0){
     91         cout << "	Error" << endl;
     92         com = s.size();
     93     }
     94     else{
     95         status.push(gotoarr[ch1][j]);//新状态进栈
     96         Status[StatusNumber] = gotoarr[ch1][j];
     97         StatusNumber++;
     98     }
     99 }
    100 void Reduction(int i, string s){//归约函数 R
    101     Output(s);
    102     cout << "r" << i << ":" << Production[i - 1] << "归约, GoTo(";
    103     int N = Production[i - 1].length() - 3;
    104     for (int j = 0; j<N; j++){//消除要归约的状态及符号
    105         status.pop();
    106         Stack.pop();
    107         StatusNumber--;
    108         stacktd.erase(stacktd.length() - 1);
    109     }
    110     cout << status.top() << "," << Production[i - 1].at(0) << ")=";
    111     Stack.push(Production[i - 1].at(0));//符号进栈
    112     stacktd = stacktd + Stack.top();
    113     Goto(status, Stack, s);
    114     cout << status.top() << "入栈" << endl;
    115     Status[StatusNumber] = status.top();
    116 }
    117 void Analyse(string s){//具体分析函数
    118     Stack.push('#');//初始化
    119     status.push(0);
    120     s = s + "#";
    121     int t = -1;//记录 ch 在数组 vt 的位置
    122     while (com<s.size()){
    123         int i = status.top();
    124         char ch = s.at(com);
    125         Judge(t, 6, vt, ch, s);
    126         if (flag == true){
    127             if (action[i][t] != "acc"&&action[i][t] != "0"){
    128                 if (action[i][t].at(0) == 'S'){
    129                     action[i][t].erase(0, 1); //删除 action[i][t]的首字母 S
    130                     Shift(atoi(action[i][t].c_str()), s);//atoi(action[i][t].c_str()), 将action[i][t]转换为整型
    131                     action[i][t].insert(0, "S");//将 S 添加回 action[i][t]
    132                 }
    133                 else if (action[i][t].at(0) == 'r'){
    134                     action[i][t].erase(0, 1);//删除 action[i][t]的首字母 r
    135                     Reduction(atoi(action[i][t].c_str()), s);//atoi(action[i][t].c_str()), 将action[i][t]转换为整型
    136                     action[i][t].insert(0, "r");//将 r 添加回 action[i][t]
    137                 }
    138             }
    139             else if (action[i][t] == "0"){
    140                 cout << "	Error" << endl;
    141                 break;
    142             }
    143             else if (action[i][t] == "acc"){
    144                 Output(s);
    145                 cout << "acc" << "	 分析成功" << endl;
    146                 break;
    147             }
    148         }
    149         else if (flag == false)
    150             break;
    151     }
    152 }
    153 int main(){
    154     string s;
    155     cout << "************************20173599周博*************************" << endl;
    156     cout << "输入的文法" << endl;
    157     for (int j = 0; j < 6; j++)
    158     {
    159         cout << Production[j] << endl;
    160     }
    161     cout << "VT:" << endl;
    162     for (int i = 0; i < 6; i++)
    163     {
    164         cout << vt[i] << "	";
    165     }
    166     cout << endl;
    167     for (int i = 0; i <3; i++)
    168     {
    169         cout << vn[i] << "	";
    170     }
    171     cout << endl;
    172     cout << "************************LR(1)分析*************************" << endl;
    173     char T;
    174         cout << "输入字符串" << endl;
    175         cin >> s;//输入要分析的字符串
    176         cout << "************************现进行如下分析*************************" << endl;
    177         cout << "步骤" << "	" << "状态栈" << "	" << "符号栈" << "	" << "剩余输入串" << "	" << "动作说明" << endl;
    178         Analyse(s);
    179         com = 0;//记录当前进行处理的输入字符串字符位置
    180         line = 1;//记录处理的步骤数
    181         stacktd = "#";
    182         StatusNumber = 1;
    183         while (!Stack.empty()){
    184             Stack.pop();
    185         }
    186         while (!status.empty()){
    187             status.pop();
    188         }
    189     
    190     return 0;
    191 }

  • 相关阅读:
    Linux 进程通信之:内存共享(Shared Memory)(转,好文章)
    进程和线程的对比和区别(转)
    CentOS下安装gdb的方法
    有关职业发展的帖子(整理)
    阿里钉钉面试题
    SSIS添加分区-动态
    java内存占用问题(一)
    网络网关TCP/IP
    java代码数组求平均值,最大值,最小值
    java代码。。。圆的面积好搞人。。。不是一般的搞人。。。欢迎指点指点
  • 原文地址:https://www.cnblogs.com/smartisn/p/12207421.html
Copyright © 2011-2022 走看看