Java实现PL0语言的词法分析器

本文介绍了编译原理课程的一个大作业——使用Java实现PL0语言的词法分析器。内容包括词法分析程序的设计,如单词符号编码、源程序预处理、构造编码表和单词识别。通过处理源程序,过滤无用符号,识别保留字、标识符、常数和运算符,构建了一个完整的词法分析流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面

编译原理课程的大作业,实现 pl0 的词法分析程序,语法分析程序,语义分析程序。

词法分析程序的编写

设计内容

处理 pl0 语言的源程序,过滤掉一些无用符号,如换行符,制表符,回车符,判断源程序中单词的合法性,分解出正确的单词,以一种二元式的形式(单词种别,单词自身的值)存储在文件中。

单词符号可以分为5种类别:基本字、标识符、常数、运算符、界符

对于 pl0 语言:

  • 基本字:beginendifthenwhiledoconstvarcallprocedureodd
  • 标识符:以字母开头,后面跟上字母或数字。
  • 常数:数字的正闭包。
  • 运算符:+-*/:=<<=>>=<>=#
  • 界符:,.;()

词法分析程序应该完成以下的功能:滤空格、识别保留字、识别标识符、拼数、拼复合词。

首先对程序中出现的单词符号做一个编码
单词符号 种别码
begin 1
end 2
if 3
then 4
while 5
do 6
const 7
var 8
call 9
procedure 10
odd 11
letter(letter|digit)* 12
digitdigit* 13
+ 14
- 15
* 16
/ 17
:= 18
< 19
<= 20
> 21
>= 22
<> 23
= 24
# 25
, 26
; 27
( 28
) 29
: 30
. 0
读入源程序
char[] source = new char[8000];
// 开启文件流,读入文件
try(BufferedReader reader = new BufferedReader(new FileReader("./src/source.txt"));){
   
   
            reader.read(source);
} catch(IOException e){
   
   
	e.printStackTrace();
}
对源程序做预处理,去除掉注释、换行符等

对源程序做一个总体的扫描,当扫描到\,可能是单行注释,也可能是除号;扫描到(时,可能是括号,也可能是多行注释;当扫描到\n\t\r这些无用符号时,略过。

// 首先,对输入源程序做预处理,处理掉注释、换行符、制表符等等
    public char[] preProcess(char[] source) throws IllegalArgumentException{
   
   
        // 构造一个临时数组存储预处理后的源程序
        char[] temp = new char[8000];
        int count = 0;

        // 逐个扫描源程序中的字符
        outLoop: for (int i=0; i<source.length; i++){
   
   
            switch (source[i]){
   
   
                // 去除单行注释
                case '/':
                    if (source[i+1] == '/'){
   
   
                        // 跳过单行注释
                        i = i+2;
                        // 跳过这一行,直到遇到回车换行
                        while (source[i] != '\n'){
   
   
                            i++;
                        }
                    } else{
   
   
                        temp[count++] = source[i];
                    }
                    break;
                // 去除多行注释
                case '(':
                    if (source[i+1] == '*'){
   
   
                        // 跳过多行注释符号
                        i = i+2;
                        // 当不满足匹配多行注释的时候,跳过
                        while (!(source[i] == '*' && source[i+1] == ')')){
   
   
                            i++;
                            // 检查有没有到程序的末尾
                            if (i >= source.length -2){
   
   
                                throw new IllegalArgumentException("源程序的注释不匹配!");
                            }
                        }
                        // 跳过多行注释符号
                        i = i+2;
                    } else{
   
   
                        temp[count++] = source[i];
                    }
                case '\n':
                case '\t':
                case '\r':
                    i++;
                    break;
                // 程序结束标志
                case '.':
                    temp[count++] = source[i];
                    break outLoop;
                default:
                    temp[count++] = source[i];
            }
        }

        // 设置源程序的长度为count
        this.length = count;
        return temp;
    }

下面就可以开始进行单词符号的识别了。

构造编码表

使用map映射来构造一个单词的编码表:

keyWords = new HashMap<>();
keyWords.put("begin", 1);
keyWords.put("end", 2);
...
keyWords.put(")", 29);
keyWords.put(":", 30);
单词识别

首先要去除掉空格,主要分为三种情况:首字符为字母,首字符为数字,首字符为其他符号。

  • 首字符为字母:判断是否全为字母,如果全为字母,就是保留字,否则就是标识符。
  • 首字符为数字:判断是否全为数字,如果是,就是常数,否则就是非法单词。
  • 首字符为其他:使用switch语句判断。

这里函数的参数为待分析代码的字符数组,分析的开始位置,Token为自定义的类,有String类型的值和int类型的值两个属性,标识识别出单词的值和种别码。

// 识别单词符号
    public Token scanner(char[] code, int begin){
   
   
        // 我们知道,要识别的PL/0语言中的单词符号有这几个类别:
        // 保留字、标识符、常数、运算符和界符
        // 可以进一步粗分为3类,字母开头(保留字和标识符)数字开头(常数)其他

        // 存储当前识别的单词符号
        char[] token = new 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值