首页 > 其他分享 >编译原理:词法分析实验

编译原理:词法分析实验

时间:2023-06-10 20:22:43浏览次数:28  
标签:return Keyword Symbol 词法 编译 comma 原理 Identifier

实验二 词法分析

实验目的

  • 根据 PL/0 语言的文法规范,编写 PL/0 语言的词法分析程序。
  • 通过设计调试词法分析程序,实现从源程序中分出各种单词的方法; 加深对课堂教学的理解;提高词法分析方法的实践能力。
  • 掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示 文件的法。
  • 掌握词法分析的实现方法。 上机调试编出的词法分析程序。

主要思想:

  • IO:实际的词法分析应当是对输入的文本文件进行检测,因此将IO重定向至文件。读入文件后,首先在main函数中逐行分割文本,再将每一行的文本分别送入检测器。

  • 词法检测:我们使用的方法是设计一个状态机进行检测。我们设置了以下几种状态:

    public enum WordState {
        START,WORD,INT,FLOAT,OPERATE,OPERATE2,SYMBOL,WORDEND,INTEND,INVALID,
        FLOATEND,OPERATEEND,SYMBOLEND;
    }
    

    其中前七种状态分别代表初态、检测到单词、整数、浮点数、操作符1(除了=)和=(这是因为当识别到除了=之外的操作符时匹配已经完成,但是匹配到=后,需要再检测其后是否为=,若是则组成==,若不是则结束,因此需要额外设置一个状态),以及非操作符。

    之后的状态(XXEND)则分别代表在前七种状态下识别到其他符号,所进入的终态。一旦我们检测到状态机进入了终态,就可以根据对应的终态获得该单词属于什么类别,从而输出结果了。

    从上述可知,该状态机中最重要的问题是如何根据输入改变状态。我们编写下面的函数用于改变状态机的状态:

    static WordState transfer(WordState state,char c)
    

    该函数定义较长且多为分支选择,因此不再赘述而简要说明其原理。该函数中传入的参数分别为当前状态机的状态,以及下一个输入字符,函数将根据这两个参数进行状态转移。

    例如,当前状态为初态(START)时,若接收到的字符c是字母,则可以断定正常情况下这是用户输入了单词,因此状态转移至单词(WORD);若接收到的是数字,则有两种可能,该词为整数或浮点数,这将由之后状态机是否接受到"."决定,因此我们现在直接状态转移至INT;若接收到的是< > = ! 则为操作数,转移至OPERATE;若收到的是空格(' '),则说明下个单词即将开始,状态仍为START

    再比如,当前状态为单词(WORD)时,若接收到的是字母、数字或下划线,则符合文法中对单词的定义,因此其状态仍是WORD;若其接收到了除此之外的符号,则说明单词已经输完,应当转而判别和输出了,因此进入WORDEND状态。

    其余状态转移与此原理相同,不再赘述。

  • 全句判别与结果输出:当状态机进入终态后要输出,其中函数void outPut()完成格式化输出工作,函数void checkString(String s)完成重新设置初态、清空缓存的工作。

重要代码定义

public enum WordState {
    START,WORD,INT,FLOAT,OPERATE,OPERATE2,SYMBOL,WORDEND,INTEND,INVALID,
    FLOATEND,OPERATEEND,SYMBOLEND;

    static WordState transfer(WordState state,char c){
        switch (state){
            case WORD:
                if(Character.isLetter(c)||Character.isDigit(c)||c=='_') //回到本状态
                    return WORD;
                else
                    return WORDEND;
            case INT:
                if(Character.isDigit(c))
                    return INT;
                else if(Character.isLetter(c))
                    return INVALID;
                else if(c=='.')
                    return FLOAT;
                else return INTEND;
            case FLOAT:
                if (Character.isLetter(c))
                    return INVALID;
                if (Character.isDigit(c))
                    return FLOAT;
                else return FLOATEND;
            case OPERATE:
                if (c=='=')
                    return OPERATE2;
                else return SYMBOLEND;
            case START:
                if (Character.isLetter(c))
                    return WORD;
                else if (Character.isDigit(c))
                    return INT;
                else if (c=='='||c=='>'||c=='<'||c=='!')
                    return OPERATE;
                else if (c==' ')
                    return START;
                else return SYMBOL;
            case OPERATE2:
                return OPERATEEND;
            case SYMBOL:
                return SYMBOLEND;

            default: return state;
        }
    }
}

运行结果:

用于测试的输入文本:

test1:

int main() {
    int i,j,k,sum = 0;
    for(i = 0;i<10;i++)
        sum++;
    return 0;
}

结果:

(Keyword,int)
(Identifier,main)
(Lparen ,()
(rparen ,))
(Symbol,{)
(Keyword,int)
(Identifier,i)
(Symbol,,)
(Identifier,j)
(Symbol,,)
(Identifier,k)
(Symbol,,)
(Identifier,sum)
(becomes,=)
(Number,0)
(comma ,;)
(Keyword,for)
(Lparen ,()
(Identifier,i)
(becomes,=)
(Number,0)
(comma ,;)
(Identifier,i)
(lss ,<)
(Number,10)
(comma ,;)
(Identifier,i)
(plus,+)
(plus,+)
(rparen ,))
(Identifier,sum)
(plus,+)
(plus,+)
(comma ,;)
(Keyword,return)
(Number,0)
(comma ,;)

test2:

int test(char *s) {
    s = "testppp";
    double Double = 1; 
    int(23.3);
    double(3);
    
    return 0;
}

结果:

(Keyword,int)
(Identifier,test)
(Lparen ,()
(Keyword,char)
(times ,*)
(Identifier,s)
(rparen ,))
(Symbol,{)
(Identifier,s)
(becomes,=)
(Symbol,")
(Identifier,testppp)
(Symbol,")
(comma ,;)
(Keyword,double)
(Identifier,Double)
(becomes,=)
(Number,1)
(comma ,;)
(Keyword,int)
(Lparen ,()
(Number,23.3)
(rparen ,))
(comma ,;)
(Keyword,double)
(Lparen ,()
(Number,3)
(rparen ,))
(comma ,;)
(Keyword,return)
(Number,0)
(comma ,;)

test3:

void test(){
    double indicator = 100;
    while(true){
        indicator/=1.1;
        if(indicator<1)  //对indicator循环除1.1
            break;
    }
}

结果:

(Keyword,void)
(Identifier,test)
(Lparen ,()
(rparen ,))
(Symbol,{)
(Keyword,double)
(Identifier,indicator)
(becomes,=)
(Number,100)
(comma ,;)
(Keyword,while)
(Lparen ,()
(Keyword,true)
(rparen ,))
(Symbol,{)
(Identifier,indicator)
(slash,/)
(becomes,=)
(Number,1.1)
(comma ,;)
(Keyword,if)
(Lparen ,()
(Identifier,indicator)
(lss ,<)
(Number,1)
(rparen ,))
(Keyword,break)
(comma ,;)
(Symbol,})

标签:return,Keyword,Symbol,词法,编译,comma,原理,Identifier
From: https://www.cnblogs.com/czy-blogs/p/17471878.html

相关文章

  • 编译原理:语法分析
    实验三语法分析实验目的给出PL/0文法规范,要求编写PL/0语言的语法分析程序。通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。选择一种语法分析方法(递归子程序法、LL(1)分析法、算......
  • 大二上 | 计算机组成原理 · 小测试卷
    一共有两张图片:(任国林老师:听我说谢谢你......
  • mysql 主从复制 原理
     mysql主从复制定义mysql主从复制是一种数据同步的技术,它可以让一个或多个从数据库(slave)复制主数据库(master)的数据变化。这样可以提高数据库的可用性、性能和扩展性,也可以实现读写分离和数据备份。mysql主从复制原理mysql主从复制的原理是基于二进制日志(binlog)的,主数据库......
  • mysql MVCC 原理
    MVCC的定义MVCC,即多版本并发控制,是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。MVCC的目的是为了提高数据库的并发性能,用更好的方式去处理读写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。MVCC的目的在MySQL中,InnoDB......
  • DevExpress源码编译(部分翻译)
    环境准备(DevExpressv18.2~22.2):vs2015至2022版本.netframework4.7.2或更高(实际我们项目用4.5.2可以编译)asp.netmvc3(devexpressmvc项目)在devexpress安装目录下(默认C:\ProgramFiles\DevExpress(version)\Components\)创建dlls目录,复制以下依赖。Microsoft.VisualStu......
  • 地址空间以及编译模式
    Linux下32位环境的用户空间内存分布: Linux下64位环境的用户空间内存分布:前面讲到,在64位环境下,虚拟地址虽然占用64位,但只有最低48位有效。故从0000800000000000~FFFF800000000000,棕色FFFF所代表的这十六位就变成了无效区域(未定义)。 程序代码区用来保存函数体的二进制代码......
  • 关于AWS-EC2-EBS-快照-或者AMI-创建的过程及原理
    对于AWSEC2的EBS创建快照Snapshot的原理逻辑,主要如下快照是异步制作的;时间点快照是立即创建的,但在快照完成(当所有已修改数据块都已转移到AmazonS3时)之前,其状态为 pending,很多大型初始快照或后续快照(其中的数据块已更改)可能需要几个小时才能完成。执行期间,正在进行的快照......
  • Windows桌面水印去除工具Universal Watermark Disabler原理分析及实现
    1.背景  最近做驱动开发,开启了系统测试模式,于是桌面的右下角就有一个水印,如下图:  测试了网上修改注册表方法不起作用,最后找到一款工具UniversalWatermarkDisabler可以把水印去除掉。于是对其原理有些兴趣,就有了相关的分析及编程实现。2、相关分析2.1相关行为分析  ......
  • 编译原理面试题
    1、请解释编译器前端和后端的区别,并描述它们在编译过程中的职责。编译器是将高级程序语言转换为目标机器语言的软件工具。它通常由两个主要组件组成:前端和后端。编译器前端:编译器前端主要负责源代码的分析和处理。它包括以下阶段:词法分析(LexicalAnalysis):将源代码分解成标记......
  • IDEA编译和构建JavaWeb项目时,项目中没有target目录,且out目录下classes文件下main包下
    问题如下:1.我们在添加web框架时,如图:2.在添加完框架,和配置完Tomcat我们开始运行项目,发现没有target文件和out文件下classes文件下什么都没有原因:出现这种情况,很可能是因为未加载的模块出现在了iml文件中,导致生成taget的时候出错,进而导致out文件内class文件的......