編譯原理系列 實驗三自下而上語法分析


系列第三彈!

實驗三 自下而上語法分析

實驗目的

  • 給出 PL/0 文法規范,要求編寫 PL/0 語言的語法分析程序。
  • 通過設計、編制、調試一個典型的自下而上語法分析程序,實現對詞法分析程序所提供的單詞序列進行語法檢查和結構分析,進一步掌握常用的語法分析方法。
  • 選擇最有代表性的語法分析方法,如算符優先分析法、LR 分析法;或者調研語法分析器的自動生成工具 YACC 的功能與工作原理,使用 YACC 生成一個自底向上的語法分析器。

題目

【問題描述】
考慮到大家用的編程語言不同,且實驗一有少數同學沒有得到正確結果,為不影響實驗三的開展,實驗三的輸入統一采用詞法分析器的輸出結果為輸入,輸入形式如下:
【輸入形式】
(lparen,()
(ident,a)
(plus,+)
(number,15)
(rparen,))
(times,*)
(ident,b)
【輸出形式】
對於語法正確的表達式,報告“語法正確”,輸出為“Yes,it is correct.”
對於語法錯誤的表達式,報告“語法錯誤”,輸出為“No,it is wrong.”
【樣例輸入】

(lparen,()
(ident,a)
(plus,+)
(number,15)
(rparen,))
(times,*)
(ident,b)

【樣例輸出】

Yes,it is correct.

【測試數據】
系統給出兩組測試數據:測試數據1:如以上樣例輸入輸出;測試數據2的輸入為:

(lparen,()
(ident,a)
(plus,+)
(number,15)
(rparen,))
(plus,+)
(times,*)
(ident,b)

測試數據2的輸出為:

No,it is wrong.

源程序

優先關系表是手工算的。

#include <iostream>
#include <string.h>
#include<bits/stdc++.h>
#define N_VT 9

using namespace std;

// 優先關系表
int findP(int a, int b) // a、b ∈ [1,9],之所以從1開始,是要適應in_vt的返回值
{
    int table[N_VT][N_VT] =  // 1表示>,-1表示<,0表示=,2表示空
        {{0,0,-1,-1,-1,-1,-1,1,1},
         {0,0,-1,-1,-1,-1,-1,1,1},
         {1,1,0,0,-1,-1,-1,1,1},
         {1,1,0,0,-1,-1,-1,1,1},
         {1,1,1,1,0,2,2,1,1},
         {1,1,1,1,2,0,2,1,1},
         {-1,-1,-1,-1,-1,-1,-1,0,1},
         {1,1,1,1,2,2,0,1,1},
         {-1,-1,-1,-1,-1,-1,-1,-1,0}};

    return table[a-1][b-1];
}

// 檢查c是否是終結符,如果不是,返回0,如果是,返回它在算符優先表中的行號(從1開始)
int in_vt(char c)
{
    int n;
    switch(c)
    {
        case 'p': n=1; break;
        case 'm': n=2; break;
        case 't': n=3; break;
        case 's': n=4; break;
        case 'i': n=5; break;
        case 'n': n=6; break;
        case 'l': n=7; break;
        case 'r': n=8; break;
        case '#': n=9; break;
        default: n=0;
    }

    return n;
}

// 判斷表達式的合法性
// p指向分析棧的首部,k指向棧頂;psc指向輸入符號
// 暫時沒有考慮到括號的匹配
int judge(char* p, int k, char* psc)
{
    if(k == 1 && p[k] == '#' && (*psc == 'p' || *psc == 'm' || *psc == 't' || *psc == 's'))
    {
        //printf("\n運算符前面沒有操作數!\n");
        return 0;
    }
    if(*psc == '#' && (*(psc-1) == 'p' || *(psc-1) == 'm' || *(psc-1) == 't' || *(psc-1) == 's'))
    {
        //printf("\n運算符后面沒有操作數!\n");
        return 0;
    }
    if(((*psc == 'p' || *psc == 'm' || *psc == 't' || *psc == 's') && ((*(psc+1) == 'p' || *(psc+1) == 'm' || *(psc+1) == 't' || *(psc+1) == 's'))))
    {
        //printf("\n運算符號相鄰!\n");
        return 0;
    }
    return 1;
}

void getinputs(char* in_c)
{
    int i = 0;
    string line;
    while(cin >> line)
    {
        in_c[i++] = line[1];
    }
    in_c[i] = '#';
}

// 總控程序
int main()
{
    // 分析棧
    char s[30] = {'\0'};
    int k = 1; // 指向棧頂
    s[k] = '#';
    s[k+1] = '\0';
    int j; // 指向棧頂終結符
    char q; // j指向的元素,即棧頂終結符


    // 輸入處理
    char in_c[50] = {'\0'}; // 輸入串
    //printf("字符串是:%s\n", in_c);
    char *psc = in_c; // 指向當前輸入符號

    int flag; // 查算符優先表得到的值(1/-1/0/2)(大於/小於/等於/空)

    // 分析總控程序
    while(1)
    {
        if(!judge(s, k, psc))
        {
            printf("No,it is wrong.");
            exit(1);
        }


        // 讓j正確指向棧頂非終結符
        if(in_vt(s[k]))
            j = k;
        else
            j = k-1;


        // 根據s[j]和*psc的優先關系,判斷移進規約
        flag = findP(in_vt(s[j]), in_vt(*psc));
        if(flag == 1) // s[j] > *psc,規約
        {
            // 找到規約范圍
            do{
                q = s[j];// q保存當前的終結符

                // j向下探一(兩)步,找到下一個終結符
                if(in_vt(s[j-1]))
                    j--;
                else
                    j-=2;
            }while(findP(in_vt(s[j]), in_vt(q)) != -1);

            // 規約
            k = j+1;
            s[k] = 'N'; // 管它規約成了哪個非終結符,不重要
            s[k+1] = '\0';

            continue;
        }
        else if(flag == -1)// s[j] < *psc,移進
        {
            k++;
            s[k] = *psc;
            s[k+1] = '\0';

            psc++;

            continue;
        }
        else if(flag == 0)
        {
            if(s[j] == '#')
            {
                printf("Yes,it is correct.");
                break;
            }
            else // 否則移進
            {
                k++;
                s[k] = *psc;
                s[k+1] = '\0';

                psc++;

                continue;
            }
        }
        else // 優先級表中空的地方
        {
            printf("No,it is wrong.");
            exit(1);
        }
    }

    return 0;
}

實驗結果

image.png
image.png


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM