燕山大学编译原理实验报告(上)

简介: 燕山大学编译原理实验报告

实验1 词法分析


1.1 实验目的


(1)理解有穷自动机及其应用。


(2)掌握 NFA 到 DFA 的等价变换方法、DFA 最小化的方法。


(3)掌握设计、编码、调试词法分析程序的技术和方法。


1.2 实验任务


编写一个程序对输入的源代码进行词法分析,并打印分析结果。自己编写一个 PL/0 词法分析程序,使用的语言为C++。


1.3 算法描述


算法描述: 首先把常用关键字放在一个数组变量里,逐个判断输入的一个字符串是否为关键字,然后根据正则表达式来判断数字,字母以及各种标识符,同时对错误的语法做出判断输出


1.4 程序结构:


Main:读入字符串


analyze:词法分析


isLetter:判断是否是字母


isKey:判断是否是关键字


主函数调用analysis,analysis中调用了剩余函数。


1.5 程序清单


#include<iostream>
using namespace std;
#define MAX 21
/*
  保留字|关键字:1
  操作符|运算符:2
  分界符:3
  标识符:4
  常数:5
  无识别:6
*/
char ch = ' ';
char* keyWord[21] = { "iostream","void","int","char","string","bool","return","using","namespace","main","break","include","begin","end","if","else","while","switch","for","else if","std" };
char takes[20];//定义获取的字符
//判断是否是关键字
bool isKey(char* takes)
{
  for (int i = 0; i < MAX; i++)
  {
    if (strcmp(takes, keyWord[i]) == 0)
      return true;
  }
  return false;
}
//判断是否是字母
bool isLetter(char letter)
{
  if ((letter >= 'a' && letter <= 'z') || (letter >= 'A' && letter <= 'Z'))
    return true;
  else
    return false;
}
//判断是否是数字
bool isDigit(char digit)
{
  if (digit >= '0' && digit <= '9')
    return true;
  else
    return false;
}
//词法分析
void analyze(FILE* fpin)
{
  while ((ch = fgetc(fpin)) != EOF) {
    if (ch == ' ' || ch == '\t' || ch == '\n') {}  //空格 回车
    else if (isLetter(ch)) {              //首是字母
      char takes[30] = { '\0' };
      int i = 0;
      while (isLetter(ch) || isDigit(ch)) {  //后面是字母或者数字
        takes[i] = ch;
        i++;
        ch = fgetc(fpin);
      }
      //回退一个指针
      fseek(fpin, -1L, SEEK_CUR);
      if (isKey(takes)) {
        //关键字
        cout << takes << "\t\t1" << "\t关键字" << endl;
      }
      else {
        //标识符
        cout << takes << "\t\t4" << "\t标识符" << endl;
      }
    }
    else if (isDigit(ch) || (ch == '.'))  //首是数字或者点
    {
      bool mark = true;
      int i = 0;
      char takes[20] = { '\0' };
      while (isDigit(ch) || isLetter(ch) || (ch == '.' && isDigit(fgetc(fpin))))
      {
        if (isLetter(ch))
        {
          mark = false;
          if (ch == '.')fseek(fpin, -1L, SEEK_CUR);
          takes[i] = ch;
          i++;
          ch = fgetc(fpin);
        }
        else {
          if (ch == '.')fseek(fpin, -1L, SEEK_CUR);
          takes[i] = ch;
          i++;
          ch = fgetc(fpin);
        }
      }
      fseek(fpin, -1L, SEEK_CUR);
      //属于无符号常数
      if (mark)
      {
        cout << takes << "\t\t5" << "\t常数" << endl;
      }
      else
        cout << takes << "\t\t7" << "\t错误的标识符" << endl;
    }
    else switch (ch) {
      //运算符
    case '+': {
      ch = fgetc(fpin);
      if (ch == '+')cout << "++" << "\t\t2" << "\t运算符" << endl;
      else {
        cout << "+" << "\t\t2" << "\t运算符" << endl;
        fseek(fpin, -1L, SEEK_CUR);
      }
    }break;
    case '-': {
      ch = fgetc(fpin);
      if (ch == '-')cout << "--" << "\t\t2" << "\t运算符" << endl;
      else {
        cout << "-" << "\t\t2" << "\t运算符" << endl;
        fseek(fpin, -1L, SEEK_CUR);
      }
    }break;
    case '*':cout << ch << "\t\t2" << "\t运算符" << endl; break;
    case '/':cout << ch << "\t\t2" << "\t运算符" << endl; break;
      //分界符
    case '\"':cout << ch << "\t\t2" << "\t分界符" << endl; break;
    case '(':cout << ch << "\t\t3" << "\t分界符" << endl; break;
    case ')':cout << ch << "\t\t3" << "\t分界符" << endl; break;
    case '[':cout << ch << "\t\t3" << "\t分界符" << endl; break;
    case ']':cout << ch << "\t\t3" << "\t分界符" << endl; break;
    case ';':cout << ch << "\t\t3" << "\t分界符" << endl; break;
    case '{':cout << ch << "\t\t3" << "\t分界符" << endl; break;
    case '}':cout << ch << "\t\t3" << "\t分界符" << endl; break;
      //运算符
    case '=': {
      ch = fgetc(fpin);
      if (ch == '=')cout << "==" << "\t\t2" << "\t运算符" << endl;
      else {
        cout << "=" << "\t\t2" << "\t运算符" << endl;
        fseek(fpin, -1L, SEEK_CUR);
      }
    }break;
    case '#': {
      ch = fgetc(fpin);
      if (ch == '=')cout << "#=" << "\t\t2" << "\t运算符" << endl;
      else {
        cout << "#" << "\t\t2" << "\t运算符" << endl;
        fseek(fpin, -1L, SEEK_CUR);
      }
    }break;
    case ':': {
      ch = fgetc(fpin);
      if (ch == '=')cout << ":=" << "\t\t2" << "\t运算符" << endl;
      else {
        cout << ":" << "\t\t2" << "\t运算符" << endl;
        fseek(fpin, -1L, SEEK_CUR);
      }
    }break;
    case '>': {
      ch = fgetc(fpin);
      if (ch == '=')cout << ">=" << "\t\t2" << "\t运算符" << endl;
      else {
        cout << ">" << "\t\t2" << "\t运算符" << endl;
        fseek(fpin, -1L, SEEK_CUR);
      }
    }break;
    case '<': {
      ch = fgetc(fpin);
      if (ch == '=')cout << "<=" << "\t\t2" << "\t运算符" << endl;
      else {
        cout << "<" << "\t\t2" << "\t运算符" << endl;
        fseek(fpin, -1L, SEEK_CUR);
      }
    }break;
      //无识别
    default: cout << ch << "\t\t6" << "\t无识别符" << endl;
    }
  }
}
int main() {
  char input[30];
  FILE* fpin;
  cout << "请输入源文件名:\n" << endl;
  for (;;) {
    cin >> input;
    if ((fpin = fopen(input, "r")) != NULL)
      break;
    else
      cout << "路径输入错误" << endl;
  }
  cout << "词法分析结果:      " << endl;
  analyze(fpin);
  fclose(fpin);
}


1.6 主要变量说明:


#define MAX 21 //定义关键字数量
char takes[20];//定义获取的字符
char*keyWord[21]={"iostream","void","int","char","string","bool","return","using","namespace","main","break","include","begin","end","if","else","while","switch","for","else if","std"};//保存关键字


1.7 调试情况


一个含C++源码的文本文件


调试情况及运行结果截图:


顺利执行,同时错误的语法也可以进行正确的判断


1.8 心得体会


通过完成词法分析程序的过程,更加深入的了解和复习了C++的使用方法,某些函数的运用,以及字符串的提取判别,文件流读取操作等等,也在调用函数过程中出现了许多的问题,通过请教同学和查阅资料都得到了解决.学习了新的函数,对C++有了更加充实的认知.


实验2 基于LL(1)方法的语法分析程序


2.1 实验目的


设计、编制和调试一个典型的语法分析方法,进一步掌握常用的语法分析方法。


2.2 实验要求


根据LL(1)分析法编写一个语法分析程序,直接输入根据已知文法构造的分析表M;


(1)程序具有通用性


所开发的程序可适用于任意输入串,且能判断该文法是否为LL(1)文法。


(2)有运行实例


对于输入符号串,所编制的语法分析程序应能正确判断此串是否为文法的句子,并要求输出分析过程。


2.3 算法描述


给定文法G[S]:表 示 空 串 S − > A T A − > B U T − > + A T ∣ 表示空串 S->AT A->BU T->+AT|表示空串S−>ATA−>BUT−>+AT∣


U->*BU|$


B->(S)|m


计算First集与Follow集合,先建立分析表,读入字符串,初始化分析栈,进入分析函数。


从左到右扫描输入串,采用最左推导,且每次直接推导只向前看一个输入符号,确定选择的规则。用一个变量记录步骤数量,及时输出。用一个变量记录输入字符串下标,作为指针的作用,控制String输出。


从分析栈中取栈顶,判断是否为非终结符号 。若是,找到栈顶在分析表中对应的规则。若为null,报错。存在,则执行输出;若不是,则判断其与输入式子头字符是否相同,相同,则输出匹配。继续读取栈顶,循环直至到底。


2.4 程序结构


Main:读入字符串


Analysis:分析函数


findH:寻找非终结符下标


findL:寻找终结符下标


Error:报错函数


主函数调用analysis,analysis中调用了剩余函数。


2.5 主要变量说明


LL1:LL1文法分析表


H:非终结符


L:终结符


Cmp:分析栈


Str:输入式


2.6 程序清单


#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <stack>
using namespace std;
//表格数组
char LL1[50][50][100] = { {"->AT", "->AT", "null", "null", "null", "null"},
             {"->BU", "->BU", "null", "null", "null", "null"},
             {"null", "null", "->$", "->+AT", "null", "->$"},
             {"null", "null", "->$", "->$", "->*BU", "->$"},
             {"->m", "->(S)", "null", "null", "null", "null"} };
char H[200] = "SATUB";
char L[200] = "m()+*#";
stack<char> cmp;
int findH(char a)
{                               //在H中找规则左部
  for (int i = 0; i < 5; i++) //找到对应行
  {
    if (a == H[i])
      return i;
  }
  return -1;
}
int findL(char b)
{                               //在L中找 找到对应列
  for (int i = 0; i < 6; i++) //找到对应列
  {
    if (b == L[i])
      return i;
  }
  return -1;
}
int error(int i, int cnt, int len, char p[], char str[])
{
  //输入的第i个符号 执行第cnt步 输入len长 第一列p列内容 str输入表达式
  printf("%d\t%s\t", cnt, p);
  for (int q = i; q < len; q++)
  {
    cout << str[q];
  }
  printf("\t报错\n");
  return len;
}
void analyze(char str[], int len)
{
  //pindex记录stack长度,p为分析栈状态
  int cnt = 1; //输出Step专用
  int i = 0;
  char p[200] = "#S"; //输出stack专用
  int pindex = 2;
  printf("Step\tStack\tString\tRule\n"); //输出制表
  while (i < len)
  {
    int x, y;
    char ch = cmp.top(); //是规则右部分 出栈
    if (ch >= 'A' && ch <= 'Z')
    {
      cmp.pop();
      x = findH(ch);
      y = findL(str[i]);
      if (x != -1 && y != -1)
      {
        int len2 = strlen(LL1[x][y]);
        if (strcmp(LL1[x][y], "null") == 0)
        {
          i = error(i, cnt, len, p, str);
          continue;
        }
        printf("%d\t%s\t", cnt, p);
        if (p[pindex - 1] != '#')
        {
          p[pindex] = '\0';
          pindex--;
        }
        if (LL1[x][y][2] != '$')
        {
          for (int q = len2 - 1; q > 1; q--)
          {
            p[pindex++] = LL1[x][y][q];
            cmp.push(LL1[x][y][q]); //放更新了的字符
          }
        }
        else
        {
          p[pindex] = '\0';
          pindex--;
        }
        for (int q = i; q < len; q++)
          cout << str[q];
        printf("\t%c%s\n", ch, LL1[x][y]);
      }
      else
      {
        i = error(i, cnt, len, p, str);
        continue; ///未找到,报错
      }
    }
    else
    {
      if (ch == str[i])
      {
        cmp.pop();
        printf("%d\t%s\t", cnt, p);
        if (ch == '#' && str[i] == '#')
        {
          printf("#\t接受\n");
          return;
        }
        for (int q = i; q < len; q++)
        {
          cout << str[q];
        }
        printf("\t%c匹配\n", ch);
        pindex--;
        p[pindex] = '\0';
        i++;
      }
      else
      {
        i = error(i, cnt, len, p, str);
        continue; ///报错
      }
    }
    cnt++;
  }
} //取下一个输入字符
int main()
{
  char str[200];
  cin >> str;
  int len = strlen(str);
  cmp.push('#');
  cmp.push('S');
  analyze(str, len + 1);
  system("pause");
  return 0;
}


2.7 调试情况


文法可以接收的语句示例:


文法不可以接收的语句示例:


根据已知文法构造的分析表,句子以及非句子均得到测试验证。


2.8 设计技巧


实现建立分析表、非终结符以及终结符数组,在匹配规则时,直接到分析表中匹配。建立一个分析栈来显示地实现非递归版本的递归下降分析,通过这个分析栈来实现回溯。在函数中通过变量指示数组位置来进行单个字符分析查找匹配。


2.9 心得体会


深入理解了LL1文法。熟悉掌握了基于LL1文法的语义分析流程。针对特定文法,需要先计算出其First及Follow集合构建LL1文法分析表,并通过分析栈来实现一步步分析。

相关文章
|
9月前
|
监控 安全 机器人
毕业论文设计题目大全(源码+论文)_kaic
毕业论文设计题目大全(源码+论文)_kaic
|
SQL 存储 数据库
数据库原理第七章课后题答案(第四版)
数据库原理第七章课后题答案(第四版)
112 0
|
SQL 存储 自然语言处理
数据库原理第三章课后题答案(第四版)
数据库原理第三章课后题答案(第四版)
289 0
|
9月前
|
C语言
C语言:初阶测试错题(查漏补缺)
C语言:初阶测试错题(查漏补缺)
52 0
|
Python
1轻松学python第一节到第五节
1轻松学python第一节到第五节
54 0
|
自然语言处理 Java 编译器
【编译原理】第一章,什么是编译原理?
【编译原理】第一章,什么是编译原理?
|
存储 缓存 搜索推荐
《现代操作系统第四版》第一章课后答案
《现代操作系统第四版》第一章课后答案
158 0
|
存储 数据库 数据安全/隐私保护
数据库原理第五章课后题答案(第四版)
数据库原理第五章课后题答案(第四版)
146 0
|
存储 安全 算法
计算机操作系统(慕课版)第一章课后题答案
计算机操作系统(慕课版)第一章课后题答案
|
消息中间件 存储 程序员
计算机操作系统(慕课版)第二章课后题答案
计算机操作系统(慕课版)第二章课后题答案

热门文章

最新文章

相关实验场景

更多