编译原理实验:词法分析

1. 实验题目:词法分析

实验目的

  1. 根据PL/0语言的文法规范,编写PL/0语言的词法分析程序;或者调研词法分析程序的自动生成工具LEX或FLEX,设计并实现一个能够输出单词序列的词法分析器。
  2. 通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学的理解;提高词法分析方法的实践能力。
  3. 掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的法。
  4. 掌握词法分析的实现方法。上机调试编出的词法分析程序。

实验内容

 已给PL/0语言文法,输出单词符号(关键字、专用符号以及其它标记)。

实验要求

  1. 把词法分析器设计成一个独立一遍的过程。
  2. 词法分析器的输出形式采用二元式序列,即:(单词种类,单词的值)

输入输出

输入:
  const a=10;
  var b,c;
  begin
  read(b);
  c:=a+b;
  write( c);
  end.
输出:
  (constsym, const)
  (ident , a)
  (eql, =)
  (number, 10)
  (semicolon, ; )
  (varsym, var)
  (ident,b)
  (comma, ,)
  (ident, c)
  (semicolon, ; )
  (beginsym, begin)
  (readsym, read )
  (lparen,( )
  (ident, b)
  (rparen, ))
  (semicolon, ; )
  (ident, c)
  (becomes, := )
  (ident, a)
  (plus, +)
  (ident,b )
  (semicolon, ; )
  (writesym,write)
  (lparen, ( )
  (ident, c)
  (rparen,) )
  (endsym, end )
  (period, .)

2. 设计思想

基本字:

单词(编码)正规式r
begin(beginsym)begin
call(callsym)call
const(constsym)const
do(dosys)do
end(endsym)end
if(ifsym)if
odd(oddsym)odd
procedure(proceduresym)procedure
read(readsym)read
var(varsym)var
while(whilesym)while
write(writesym)write
then(thensym)then
标识符:
单词(编码)正规式r
----------
<标识符>(ident)(字母)(字母 |数字)*
常数:
单词(编码)正规式r
----------
<常数>(ident)(数字)(数字)*
运算符:
单词(编码)正规式r
----------
+(plus)+
-(minus)-
*(times)*
/(slash)/
=(eql)=
<>(neq)<>
<(lss)<
<=(leq)<=

(gtr)|>
=(geq)|>=
:=(becomes)|:=
界符:
单词(编码)| 正规式r
-----|-----
( (lparen)| (
) (rparen)| )
, (comma)| ,
; (semicolon)| ;
. (period)| .

3.算法流程

在这里插入图片描述

  1. 词法分析程序打开源文件,读取文件内容,直至遇上文件结束符,然后读取结束。
  2. 接下来就要对源文件从头到尾进行扫描了,从头开始扫描,这个时候扫描程序首先要询问当前的字符是不是空格,若是空格,则继续扫描下一个字符,直至不是空格。然后询问这个字符是不是字母,若是则进行标识符和保留字的识别;若这个字符为数字,则进行数字的判断。否则,依次对这个字符可能的情况进行判断(界符和运算符),若将所有可能都走了一遍还是没有知道它是谁,则认定为错误符号,输出该无法识别error,程序结束。每次成功识别了一个单词后,单词都会存在word1[]数组中,然后字符指针往后移,进行下一个单词的识别。
  3. 主控程序需要负责对每次识别的种别码进行判断,对于不同的单词种别做出不同的反应,直至文件结束。
  4. 本次实验我采用了map这个STL关联容器,主要是考虑到词法分析中的数据映射的关系,因此采用这种结构。map提供一对一的数据处理能力,其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值。这个容器是非常方便使用的,对于查找可以直接使用迭代器进行,利用find()函数,若一直到末尾都未找到,则是不能识别或为标识符。

4. 源程序

#include<bits/stdc++.h>
using namespace std;
map<string,string> word;//应用map数据结构形成一个string->string的对应
std::map<string,string>::iterator it;//用来遍历整个对应关系的迭代器
void map_init(){//对应关系进行初始化
    word["begin"]="beginsym";
    word["call"]="callsym";
    word["const"]="constsym";
    word["do"]="dosym";
    word["end"]="endsym";
    word["if"]="ifsym";
    word["odd"]="oddsym";
    word["procedure"]="proceduresym";
    word["read"]="readsym";
    word["then"]="thensym";
    word["var"]="varsym";
    word["while"]="whilesym";
    word["write"]="writesym";
    word["+"]="plus";
    word["-"]="minus";
    word["*"]="times";
    word["/"]="slash";
    word["="]="eql";
    word["<>"]="neq";
    word["<"]="lss";
    word["<="]="leq";
    word[">"]="gtr";
    word[">="]="geq";
    word[":="]="becomes";
    word["("]="lparen";
    word[")"]="rparen";
    word[","]="comma";
    word[";"]="semicolon";
    word["."]="period";
}
int main(){
    map_init();//初始化
    char ch;
    char a;
    string word1;//string变量识别单词
    string str;//string变量进行字符识别
    ifstream infile("F:\\编译原理\\第一次实验\\analysis.txt");//文件输入流
    ofstream outfile("F:\\编译原理\\第一次实验\\result.txt");//文件输出流
    ostringstream buf;
    while(buf&&infile.get(ch)) buf.put(ch);//将文件中的字符读出来
    str= buf.str();//将得到的字符储存到string类型变量中
    int csize=str.length();
    for(int i=0;i<csize;i++){//对整个字符串进行遍历
        while(str[i]==' '||str[i]=='\n') i++;//若最开始为空格或换行符,则将指针的位置往后移
        if(isalpha(str[i])){//对标识符和基本字进行识别,调用库函数isalpha()
            word1=str[i++];
            while(isalpha(str[i])||isdigit(str[i])){
                word1+=str[i++];
            }
            it=word.find(word1);
            if(it!=word.end()){//判断是不是基本字,若为基本字则进行输出
                cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
            }
            else{//否则直接输出
                cout<<"(ident"<<","<<word1<<")"<<endl;
            }
            i--;
        }
        else if(isdigit(str[i])){//判断是不是常数,调用库函数isdigit()
            word1=str[i++];
            while(isdigit(str[i])){
                word1+=str[i++];
            }
            if(isalpha(str[i])){
                cout<<"error!"<<endl;
                break;
            }
            else{
                cout<<"(number"<<","<<word1<<")"<<endl;
            }
            i--;
        }else if(str[i]=='<'){//对<,<=分别进行判断
            word1=str[i++];
            if(str[i]=='>'){
                word1+=str[i];
                cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
            }else if(str[i]=='='){
                word1+=str[i];
                cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
            }else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
                cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
            }else{
                cout<<"error!"<<endl;
                break;
            }
            i--;
        }else if(str[i]=='>'){//对>,>=分别进行判断
            word1=str[i++];
            if(str[i]=='='){
                word1+=str[i];
                cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
            }else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
                cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
            }else{
                cout<<"error!"<<endl;
                break;
            }
            i--;
        }else if(str[i]==':'){//对:=进行判断
            word1=str[i++];
            if(str[i]=='='){
                word1+=str[i];
                cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
            }else{
                cout<<"error!"<<endl;
                break;
            }
            i--;
        }else{//对其他的基本字依次进行判断
            word1=str[i];
            it=word.find(word1);
            if(it!=word.end()){
                cout<<"("<<word[word1]<<","<<word1<<")"<<endl;
            }else{
                cout<<"error!"<<endl;
                break;
            }
        }
    }
    infile.close();
    return 0;
}

5. 调试数据

待输入的文件流:
在这里插入图片描述
输出数据:
在这里插入图片描述
在这里插入图片描述
说明:如上实验仅符合当时实验要求的相关条件,其他的需求略微进行更改就行,思想是一样的,还是很简单的。输入输出自己按自己需求更改即可。

【问题描述】 请根据给定的文法设计并实现词法分析程序,从源程序中识别出单词,记录其单词类别和单词值,输入输出及处理要求如下: (1)数据结构和与语法分析程序的接口请自行定义;类别码需按下表格式统一定义; (2)为了方便进行自动评测,输入的被编译源文件统一命名为testfile.txt(注意不要写错文件名);输出的结果文件统一命名为output.txt(注意不要写错文件名),结果文件中每行按如下方式组织: 单词类别码 单词的字符/字符串形式(中间仅用一个空格间隔) 单词的类别码请统一按如下形式定义: 单词名称 类别码 单词名称 类别码 单词名称 类别码 单词名称 类别码 标识符 IDENFR else ELSETK - MINU = ASSIGN 整形常量 INTCON switch SWITCHTK * MULT ; SEMICN 字符常量 CHARCON case CASETK / DIV , COMMA 字符串 STRCON default DEFAULTTK < LSS ( LPARENT const CONSTTK while WHILETK GRE [ LBRACK char CHARTK scanf SCANFTK >= GEQ ] RBRACK void VOIDTK printf PRINTFTK == EQL { LBRACE main MAINTK return RETURNTK != NEQ } RBRACE if IFTK + PLUS : COLON 【输入形式】testfile.txt中的符合文法要求的测试程序。 【输出形式】要求将词法分析结果输出至output.txt中。 【特别提醒】(1)读取的字符串要原样保留着便于输出,特别是数字,这里输出的并不是真正的单词值,其实是读入的字符串,单词值需另行记录。 (2)本次作业只考核对正确程序的处理,但需要为今后可能出现的错误情况预留接口。 (3)在今后的错误处理作业中,需要输出错误的行号,在词法分析的时候注意记录该信息。 (4)单词的类别和单词值以及其他关注的信息,在词法分析阶段获取后,后续的分析阶段会使用,请注意记录;当前要求的输出只是为了便于评测,完成编译器中无需出现这些信息,请设计为方便打开/关闭这些输出的方案。 【文法定义】请到“2020年文法定义(用于查看文法,不计入成绩)”作业中查看文法 【样例输入】 coNst int cONst1 = 001, const2 = -100; const char const3 = '_'; int change1; char change3; int gets1(int var1,int var2){ change1 = var1 + var2; return (change1); } void main(){ printf("Hello World"); printf(gets1(10, 20)); } 【样例输出】 CONSTTK coNst INTTK int IDENFR cONst1 ASSIGN = INTCON 001 COMMA , IDENFR const2 ASSIGN = MINU - INTCON 100 SEMICN ; CONSTTK const CHARTK char IDENFR const3 ASSIGN = CHARCON _ SEMICN ; INTTK int IDENFR change1 SEMICN ; CHARTK char IDENFR change3 SEMICN ; INTTK int IDENFR gets1 LPARENT ( INTTK int IDENFR var1 COMMA , INTTK int IDENFR var2 RPARENT ) LBRACE { IDENFR change1 ASSIGN = IDENFR var1 PLUS + IDENFR var2 SEMICN ; RETURNTK return LPARENT ( IDENFR change1 RPARENT ) SEMICN ; RBRACE } VOIDTK void MAINTK main LPARENT ( RPARENT ) LBRACE { PRINTFTK printf LPARENT ( STRCON Hello World RPARENT ) SEMICN ; PRINT
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值