编译原理实验一 词法分析设计

实验一 词法分析设计

实验学时:4 实验类型:综合 实验要求:必修

一、实验目的

通过本实验的编程实践,使学生了解词法分析的任务,掌握词法分析程序设 计的原理和构造方法,使学生对编译的基本概念、原理和方法有完整的和清楚的 理解,并能正确地、熟练地运用。

二、实验内容

用 VC++/VB/JAVA 语言实现对 C 语言子集的源程序进行词法分析。通过输 入源程序从左到右对字符串进行扫描和分解,依次输出各个单词的内部编码及单 词符号自身值;若遇到错误则显示“Error”,然后跳过错误部分继续显示 ;同时 进行标识符登记符号表的管理。

以下是实现词法分析设计的主要工作:

(1)从源程序文件中读入字符。

(2)统计行数和列数用于错误单词的定位。

(3)删除空格类字符,包括回车、制表符空格。

(4)按拼写单词,并用(内码,属性)二元式表示。(属性值——token 的机内 表示)

(5)如果发现错误则报告出错

6

(6)根据需要是否填写标识符表供以后各阶段使用。 单词的基本分类:

 关键字:由程序语言定义的具有固定意义的标识符。也称为保留字例如 if、 for、while、printf ; 单词种别码为 1。
 标识符:用以表示各种名字,如变量名、数组名、函数名;
 常数: 任何数值常数。如 125, 1,0.5,3.1416;

 运算符:+、-、*、/;
 关系运算符: <、<=、= 、>、>=、<>;  分界符: ;、,、(、)、[、];

三、词法分析实验设计思想及算法 1、主程序设计考虑:

 程序的说明部分为各种表格和变量安排空间。 在具体实现时,将各类单词设计成结构和长度均相同的形式,较短的关键字后面 补空。
k 数组------关键字表,每个数组元素存放一个关键字(事先构造好关键字表)。
s 数组------存放分界符表(可事先构造好分界符表)。为了简单起见,分界符、 算术运算符和关系运算符都放在 s 表中(编程时,应建立算术运算符表和关系运 算符表,并且各有类号),合并成一类。
id 和 ci 数组分别存放标识符和常数。
instring 数组为输入源程序的单词缓存。
outtoken 记录为输出内部表示缓存。
还有一些为造表填表设置的变量。
 主程序开始后,先以人工方式输入关键字,造 k 表;再输入分界符等造 p 表。
 主程序的工作部分设计成便于调试的循环结构。每个循环处理一个单词; 接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。 例如,把每一单词设计成如下形式: (type,pointer)
其中 type 指明单词的种类,例如:Pointer 指向本单词存放处的开始位置。

7

还有一些为造表填表设置的变量。
 主程序开始后,先以人工方式输入关键字,造 k 表;再输入分界符等造 p 表。
 主程序的工作部分设计成便于调试的循环结构。每个循环处理一个单词; 接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。 例如,把每一单词设计成如下形式: (type,pointer)
其中 type 指明单词的种类,例如:Pointer 指向本单词存放处的开始位置。

8

词法分析设计流程图

2、词法分析过程考虑
 根据输入单词的第一个字符(有时还需读第二个字符),

判断单词类,产生类号:以字符 k 表示关键字;id 表示标识符;
ci 表示常数;s 表示分界符。
 对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较, 如表中已有该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入 数组 id 中,将常数变为二进制形式存入数组中 ci 中,并记录其在表中的位置。 lexical 过程中嵌有两个小过程:一个名为 getchar,其功能为从 instring 中按 顺序取出一个字符,并将其指针 pint 加 1 ;另一个名为 error,当出现错误时, 调用这个过程,输出错误编号。
 要求:所有识别出的单词都用两个字节的等长表示,称为内部码。第 一个字节为 t ,第二个字节为 i 。 t 为单词的种类。关键字的 t=1;分界符 的 t=2;算术运算符的 t=3;关系运算符的 t=4;无符号数的 t=5;标识符 的 t=6。i 为该单词在各自表中的指针或内部码值。表 1 为关键字表;表 2 为

9

分界符表;表 3 为算术运算符的 i 值;表 4 为关系运算符的 i 值。

10

四、实验要求

取字符和统计字符行列位置子程序

1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。 2、将标识符填写的相应符号表须提供给编译程序的以后各阶段使用。 3、根据测试数据进行测试。测试实例应包括以下三个部分:

 全部合法的输入。
 各种组合的非法输入。  由记号组成的句子。

4、词法分析程序设计要求输出形式: 例:输入 VC++语言的实例程序:

If i=0 then n++; a<= 3b %); 输出形式为:

单词 二元序列 类型 位置(行,列)

for i
=

(单词种别,单词属性)

(1,for ) 关键字

( 6,i ) 标识符
( 4,= ) 关系运算符

(1,1) (1,2) (1,3)

11

0 then n ++ ;
a <= 3b %
)
;

( 5,0 )
( 1,then)

(6,n ) Error ( 2, ; )

(6,a ) (4,<= ) Error Error

( 2, ) ) ( 2, ; )

常数 (1,4) 关键字 (1,5) 标识符 (1,6) Error (1,7) 分界符 (1,8) 标识符 (2,1) 关系运算符 (2,2) Error (2,4) Error (2,4)

分界符 (2,5) 分界符 (2,6)

五、实验步骤

1、根据流程图编写出各个模块的源程序代码上机调试。
2、 编制好源程序后,设计若干用例对系统进行全面的上机测试,并通过所设计 的词法分析程序;直至能够得到完全满意的结果。
3、书写实验报告 ;实验报告正文的内容:
 功能描述:该程序具有什么功能?
 程序结构描述:函数调用格式、参数含义、返回值描述、函数功能;函数 之间的调用关系图。
 详细的算法描述(程序总体执行流程图)。
 给出软件的测试方法和测试结果。
 实验总结 (设计的特点、不足、收获与体会)。

import java.io.IOException;
import java.io.InputStreamReader;

public class Q1{
    private char ch;
    private StringBuilder inString = new StringBuilder();
    private StringBuilder outToken = new StringBuilder();

    private int i;
    private int j;

    private int row;
    private int line;

    public void startAnalyze() {
        while(j < inString.length()){
            getChar(); getBC();
            if(isLetter()){
                while(isLetter() || isDigit()){
                    concat(); getChar();
                }
                retract();
                if(reserve()){
                    formatPrint(1);
                }else{
//                    insertId();
                    formatPrint(6);
                }
            }else if(isDigit()){
                while(isDigit()){
                    concat(); getChar();
                }
                if (isLetter()){
                    while (isLetter()){
                        concat(); getChar();
                    }
                    retract();
                    formatPrint(0);
                    continue;
                }
                retract();
//                insertCount();
                formatPrint(5);
            }else{
                if(isOther()){
                    concat();
                    getChar();
                    if(ch != '\0'){
                        if(isOther()){
                            concat();
                        }else {
                            retract();
                        }
                    }

                    formatPrint(getType());
                }else{
                    concat();
                    formatPrint(0);
                }
            }
        }
    }

    private int getType() {
        int i = 0;
        while (i < p.length){
            if(p[i].equals(outToken.toString())){
                break;
            }
            i++;
        }
        if(i < 6){
            return 2;
        }else if(i < 10){
            return 3;
        }else if(i < 16){
            return 4;
        }else{
            boolean flag1 = false;
            boolean flag2 = false;
            for(int k = 0; k < 6; k++){
                if(p[k].charAt(0) == outToken.toString().charAt(0)){
                    flag1 = true;
                }
                if(p[k].charAt(0) == outToken.toString().charAt(1)){
                    flag2 = true;
                }
            }

            if(flag1 && flag2){
                retract();
                outToken.delete(1, 2);
                return 2;
            }
            return 0;
        }
    }

    public void getChar() {
        if(j < inString.length()){
            ch = inString.charAt(j++);
            line++;
        }else{
            ch = '\0';
        }
    }

    public void getBC(){
        while(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'){
            if(ch == '\n'){
                row++;
                line = 1;
            }
            getChar();
        }
    }

    public boolean reserve(){
        for(int i = 0; i < k.length; i++){
            if(k[i].equals(outToken.toString())) return true;
        }
        return false;
    }

    public void concat() {
        outToken.append(ch);
    }

    public void retract(){
//        if(j <= inString.length()){
        j--;
        line--;
//        }
    }

    public void insertId(){

    }

    public void insertCount(){

    }

    public boolean isDigit(){
        return Character.isDigit(ch);
    }

    public boolean isLetter(){
        return Character.isLetter(ch);
    }

    public boolean isOther(){
        for(int i = 0; i < p.length; i++){
            if(p[i].equals(String.valueOf(ch))){
                return true;
            }
        }
        return false;
    }

    public void formatPrint(int type){
        String s = outToken.toString();
        switch (type){
            case 0:
                System.out.printf("%s\tError\tError\t(%d, %d)\n", s, row, line - s.length());
                break;
            case 1:
                System.out.printf("%s\t(1, %s)\t关键字\t(%d, %d)\n", s, s, row, line - s.length());
                break;
            case 2:
                System.out.printf("%s\t(2, %s)\t分界符\t(%d, %d)\n", s, s, row, line - s.length());
                break;
            case 3:
                System.out.printf("%s\t(3, %s)\t算数运算符\t(%d, %d)\n", s, s, row, line - s.length());
                break;
            case 4:
                System.out.printf("%s\t(4, %s)\t关系运算符\t(%d, %d)\n", s, s, row, line - s.length());
                break;
            case 5:
                System.out.printf("%s\t(5, %s)\t常数\t(%d, %d)\n", s, s, row, line - s.length());
                break;
            case 6:
                System.out.printf("%s\t(6, %s)\t标识符\t(%d, %d)\n", s, s, row, line - s.length());
                break;
            default:
                break;
        }

        outToken.delete(0, outToken.length());
    }

//    private HashSet<String> id = new HashSet<>();
//    private HashSet<String> ci = new HashSet<>();

    private String[] k;
    private String[] p;

    public Q1 () throws IOException {
        k = new String[] {"do", "end", "for", "if", "printf", "scanf", "then", "while"};
        p = new String[] {",", ";", "(", ")", "[", "]", "+", "-", "*", "/", "<", "<=", "=", ">", ">=", "<>"};

        InputStreamReader reader = new InputStreamReader(Q1.class.getResourceAsStream("Q1"));

        for(int ch; (ch = reader.read()) != -1; ){
            inString.append((char)ch);
        }
        row = 1; line = 1;
    }

    public static void main(String[] args) throws IOException {
        Q1 main = new Q1();
        main.startAnalyze();
    }
}

 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值