编译原理 实验一《词法分析程序设计与实现》

一、实验目的

  • 加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程 语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。

二、实验内容

  • 自定义一种程序设计语言,或者选择已有的一种高级语言,编制它的词法分析程序。词法分析程序的实现可以采用任何一种编程语言和编程工具。
  • 从输入的源程序中,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、界符。并依次输出各个单词的内部编码及单词符号自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)

三、实验方法
1、实验使用Java语言为程序设计语言,使用文本读入输入的数据;
2、对单词的构词规则进行定义;
3、编写对每种类的单词进行识别的语句并进行单独测试;
4、绘制词法分析流程图;
5、将所有识别功能代码汇总,编写成一个整体,再进行数据测试。


四、实验步骤
1、确定单词构词规则:
关键字:main、int、char、string、bool、float、double、true、false、return、if、else、while、for、default、do、public、static、switch。关键字的内部编码为1;
标识符:①标识符由字母、数字、下划线(_)组成;②不能把C语言关键字作为标识符;③标识符对大小写敏感;④首字符只能是字母或下划线,不能是数字。标识符的内部编码为2。
常数:无符号整数值。常量的内部编码为3。
运算符:+、-、*、/、^、=、<=、>=、!=、 |、&、!、||、&&。运算符的内部编码为4;
界符:,、;、{、}、(、)。界符的内部编码为5。
2、绘制词法分析流程图
在这里插入图片描述
3、代码编写

import java.io.File;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;

import static java.lang.Character.*;

public class Analyzer {

    //关键字、界符、运算符
    private static String[] key;
    private static char[] boundSign;
    private static char[] operator;
    private static ArrayList<String> resultSet;

    //存放读入的字符
    private char ch;
    //当前读入的行
    private String strToken;

    public Analyzer(){

    }

    //初始化分析器
    private void init() throws Exception {
        //C语言常用关键字
        key = new String[]{"main","int","char","string","bool","float","double","for","default","do",
                "if","else","while","public","static","switch","true","false","return"};
        //C语言常见的界限符
        boundSign = new char[]{',', ';', '(', ')', '[', ']', '{', '}'};
        //C语言常见的操作符
        operator = new char[]{'+', '-', '*', '/', '!', '&', '^', '|', '=', '>', '<'};

        resultSet = new ArrayList<String>();

        readText();//读入文件中的字符串
    }

    //读入文件
    private void readText() throws Exception{
        File file = new File("D:\\Java\\lexical_analyzer\\text.txt");//读入文件
        List<String> ss = Files.readAllLines(file.toPath());
        for(String s : ss){
            strToken = s;
            String str = prepared(strToken);
            start(str);
        }
    }
    //判断是否是关键字
    private boolean is_key(String s){
        for(String s1 : key){
            if(s.equals(s1)) return true;
        }
        return false;
    }
    //判断是否是界符
    private boolean is_boundSign(char ch){
        for(char c1 : boundSign){
            if(ch == c1) return true;
        }
        return false;
    }
    //判断是否是运算符
    private boolean is_operator(char ch){
        for(char c1 : operator){
            if(ch == c1) return true;
        }
        return false;
    }
    //判断是否为有效字符
    private boolean is_effective(char ch){
        if(isLetter(ch) || ch == '_'){

        }else if(isDigit(ch)){//判断是否是数字

        }else if(is_boundSign(ch)){//判断是否为界符

        }else if(is_operator(ch)){//判断是否是操作符

        }else {
            return false;
        }
        return true;
    }

    //对输入的代码先进行预处理,删除多余空格和注释
    private String prepared(String strToken) {
        strToken = strToken.trim() + " ";
        String str = " ";
        //经过第一次扫描,把代码中间的多个空格变成一个
        //i为当前指的单词开头,j是指的单词结尾的后一个空格
        for(int i = 0, j = 0; j < strToken.length(); ){
            while(strToken.charAt(j) != ' ' && j < strToken.length() - 1) j++;
            str = str + strToken.substring(i, j + 1);
            i = j;
            while(strToken.charAt(i) == ' ' && i < strToken.length() - 1) i++;
            j = i + 1;
        }
        //第二次扫描去除注释
        for(int i = 0; i < str.length() - 1; i++){
            if(str.charAt(i) == '/' && str.charAt(i + 1) == '/'){
                str = str.substring(0, i);
                break;
            }
        }
        str = str.trim();
        return str;
    }

    //主方法,功能逻辑入口,完成词法分析
    private void start(String strToken){
        if(!strToken.equals("")){
            //存放结果
            String result;
            //最后留一个空格,单词识别
            strToken += " ";
            //记录读到的字符的位置
            int resultIndex = 0;
            //去掉无效字符
            while (!is_effective(strToken.charAt(resultIndex)) && strToken.charAt(resultIndex) != ' ') resultIndex ++;
            //记录无效字符
            if(resultIndex != 0){
                resultSet.add("( error , \"" + strToken.substring(0,resultIndex) + "\" )" );
            }
            //读入第一个有效字符
            ch = strToken.charAt(resultIndex ++);
            //将字符存放到结果字符串中
            result = String.valueOf(ch);

            while (resultIndex <= strToken.length()){
                //判断是否为字母或下划线
                if(isLetter(ch) || ch == '_'){
                    if(is_key(result.trim())){
                        resultSet.add("( 1 , \"" + result.trim() + "\" )");
                        result = " ";
                    }
                    //继续读入字母、数字、下划线,可以组成标识符或关键字
                    while(isLetter(strToken.charAt(resultIndex)) || strToken.charAt(resultIndex) == '_' || isDigit(strToken.charAt(resultIndex))){
                        result += strToken.charAt(resultIndex ++);
                    }
                    //判断将这个单词全部读入后是否是关键字,如果不是关键字的话,那只可能是标识符
                    if(is_key(result.trim())){
                        resultSet.add("( 1 , \"" + result.trim() + "\" )");
                        result = " ";
                    }else{
                        resultSet.add("( 2 , \"" + result.trim() + "\" )");
                        result = " ";
                    }
                    //标识符或关键字后面可能不加空格跟着界符或者运算符
                    if(is_boundSign(strToken.charAt(resultIndex))){//跟着界符
                        resultSet.add("( 5 , \"" + strToken.charAt(resultIndex ++) + "\" )");
                    }else if(is_operator(strToken.charAt(resultIndex))){//运算符
                        result += strToken.charAt(resultIndex ++);
                        while (is_operator(strToken.charAt(resultIndex))){
                            result += strToken.charAt(resultIndex ++);
                        }
                        resultSet.add("( 4 , \"" + result.trim() + "\" )");
                        result = " ";
                    }
                }else if(isDigit(ch)){//判断是否是数字
                    //如果还是数字就继续加入
                    while (isDigit(strToken.charAt(resultIndex))){
                        result += strToken.charAt(resultIndex ++);
                    }
                    //加入结果集
                    resultSet.add("( 3 , \"" + result.trim() + "\" )");
                    result = " ";

                }else if(is_boundSign(ch)){//判断是否为界符
                    resultSet.add("( 5 , \"" + ch + "\" )");

                }else if(is_operator(ch)){//判断是否是运算符
                    while (is_operator(strToken.charAt(resultIndex))){
                        result += strToken.charAt(resultIndex ++);
                    }
                    resultSet.add("( 4 , \"" + result.trim() + "\" )");
                    result = " ";
                }

                if(resultIndex >= strToken.length() - 1){//判断是否已经到达边界
                    break;
                }else {
                    while (strToken.charAt(resultIndex) == ' ') resultIndex ++;//空格跳过
                    ch = strToken.charAt(resultIndex ++);//读入下一个字符
                    if(is_effective(ch)){//判断是否为有效字符
                        result = result + ch;
                    }else {
                        int resultIndexL = resultIndex - 1;
                        while (!is_effective(strToken.charAt(resultIndex))) resultIndex ++;
                        resultSet.add("( error ,\"" + strToken.substring(resultIndexL,resultIndex) + "\" )" );
                        ch = strToken.charAt(resultIndex ++);
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Analyzer analyzer = new Analyzer();
        //初始化
        analyzer.init();
        //打印结果集
        for (String tmp : resultSet){
            System.out.println(tmp);
        }
    }
}

五、实验结果
测试数据如下图所示
在这里插入图片描述
输出结果
在这里插入图片描述在这里插入图片描述
输出结果符合实验预期,代码测试成功。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值