编译原理:C#词法分析器实现 C#代码实现

西南石油大学的编译原理课程实验一代码如下:
代码是在老师的基础上增加了制表符,就是空格回车等等,然后还有就是判断数字等等的代码。
在这里插入图片描述
修改的代码如下
1、乘法和乘方的代码如下在这里插入图片描述
2、当输入是数字或者小数的时候的处理代码
在这里插入图片描述
3、加减乘除代码
在这里插入图片描述
4、过滤空白字符代码
在这里插入图片描述

源代码如下:

using System;
using System.IO;

namespace scanner
{
    //记号类别号
    enum Token_Type
    {
        ORIGIN, SCALE, ROT, IS, TO, //语言保留字(一字一类别)
        STEP, DRAW, FOR, FROM,      //语言保留字
        T,                          //语言中唯一的变量
        ID,                         //标识符(若把关键字、变量都看成一种单词,可以使用本类别)
        ZHIBIAOFU,                   //制表符,空格回车等等
        SEMICO, L_BRACKET, R_BRACKET, COMMA, //分隔符(分号、左括号、右括号、逗号)
        PLUS, MINUS, MUL, DIV, POWER,        //运算符(加、减、乘、除、乘方)

        FUNC,                                //(语言提供的标准数学)函数

        CONST_ID,                           //数值常量
        ERRTOKEN,                           //错误单词
        NONTOKEN							//专用记号(单词序列结束)
    };

    //记号数据类型
    delegate double MathFunc(double d);//单参数的函数委托类型
    struct Token
    {
        public Token_Type type; 			//类别号
        public string lexeme;				//标识符的字符串
        public double value;				//数值常数的值
        public MathFunc func; 	            //函数委托

        public Token(Token_Type type = Token_Type.NONTOKEN, string lexeme = "", double value = 0, MathFunc func = null)
        {
            this.type = type;
            this.lexeme = lexeme;
            this.value = value;
            this.func = func;
        }
    }

    class Program
    {
        // 预定义单词表
        static Token[] TokenTab = {
            //符号常数
            new Token(Token_Type.CONST_ID,  "PI",       3.1415926,  null),
            new Token(Token_Type.CONST_ID,  "E",        2.71828,    null),
            //变量(惟一的)
            new Token(Token_Type.T,         "T",        0.0,        null),
            //数学函数
            new Token(Token_Type.FUNC,      "SIN",      0.0,        Math.Sin),
            new Token(Token_Type.FUNC,      "COS",      0.0,        Math.Cos),
            new Token(Token_Type.FUNC,      "TAN",      0.0,        Math.Tan),
            new Token(Token_Type.FUNC,      "LN",       0.0,        Math.Log),
            new Token(Token_Type.FUNC,      "EXP",      0.0,        Math.Exp),
            new Token(Token_Type.FUNC,      "SQRT",     0.0,        Math.Sqrt),
            //语句关键字
            new Token(Token_Type.ORIGIN,    "ORIGIN",   0.0,        null),
            new Token(Token_Type.SCALE,     "SCALE",    0.0,        null),
            new Token(Token_Type.ROT,       "ROT",      0.0,        null),
            new Token(Token_Type.IS,        "IS",       0.0,        null),
            new Token(Token_Type.FOR,       "FOR",      0.0,        null),
            new Token(Token_Type.FROM,      "FROM",     0.0,        null),
            new Token(Token_Type.TO,        "TO",       0.0,        null),
            new Token(Token_Type.STEP,      "STEP",     0.0,        null),
            new Token(Token_Type.DRAW,      "DRAW",     0.0,        null)
        };
        static Token ErrorToken = new Token(Token_Type.ERRTOKEN, "error token", -1, null);

        //c# 无 ungetc 函数(将一个字符退回输入流),所以用如下代码模拟
        static char lastCh;
        static bool ungetFlag = false;
        //读取一个字符
        static char getChar(StreamReader sr)
        {
            if (!ungetFlag)
            {
                lastCh = (char)sr.Read();
            }
            else
                ungetFlag = false;

            return lastCh;
        }
        //退回一个字符
        static void ungetChar(StreamReader sr)
        {
            ungetFlag = true;
        }
        //c 语言的 ungetc 函数,在 c# 中的模拟

        //判断标识符是否语言的预定义单词
        static Token IsKeyWords(string id)
        {
            int i;
            Token token = new Token();

            for (i = 0; i < TokenTab.Length; i++) if (string.Equals(TokenTab[i].lexeme, id)) break;

            if (i < TokenTab.Length)
                token = TokenTab[i];
            else
                token = ErrorToken;

            return token;
        }

        //显示单词
        static void writeToken(Token token)
        {
            if (token.type == Token_Type.FUNC)
                Console.WriteLine("{0,-15}{1, -15}{2, -15}{3, -20}", (int)token.type, token.lexeme, token.value, (string)token.func.Method.Name);
            else
                Console.WriteLine("{0,-15}{1, -15}{2, -15}{3, -20}", (int)token.type, token.lexeme, token.value, "");
        }

        static void Main(string[] args)
        {
            Console.WriteLine("{0,-11}{1, -12}{2, -12}{3, -20}", "记号类别", "字符串", "常数值", "函数指针");
            Console.WriteLine("-------------------------------------------------------");

            //打开源代码文件
            StreamReader sr;
            if (args.Length == 0)
            {
                sr = File.OpenText("p89-8-10.draw");//文件必须放在项目的子目录 bin\debug 下
            }
            else
            {
                sr = File.OpenText(args[0].ToString());//允许通过命令行参数,给出源代码文件名
            }

            //从源代码文件中逐个读取字符
            Token token;
            char c, preCh;
            while (true)
            {
                c = getChar(sr);//读取字符

                //消除注释内容
                if (c == '-' || c == '/')
                {	//当前输入字符是 - 或 /,说明可能遇到注释引导符了
                    preCh = c;		//暂存已读字符
                    c = getChar(sr);//读取新字符
                    if (c == preCh)
                    {	//新字符 = 已读字符:是注释引导 -- 或 //
                        //逐一读入注释文本(以换行符或文件终止符为结束),不作任何处理,即忽略掉注释
                        while (c != '\n' && !sr.EndOfStream) c = getChar(sr);

                    }
                    else
                    {			//新字符 ≠ 已读字符:不是注释引导
                        ungetChar(sr);//将多读的这个字符退回输入流
                        c = preCh;	  //恢复为暂存字符(暂存的 - 或 / 是运算符,需作为记号处理)
                    }
                }
                if (sr.EndOfStream)//文件读取结束,添加一个结束单词
                {
                    token = new Token(Token_Type.NONTOKEN);
                    break;
                }

                //需要添加代码:过滤空白字符(\t:制表符,\n:换行符,\r:回车符,空格)

                if (c == '+')
                {			//加号
                    token = new Token(Token_Type.PLUS, "+");

                }
                else if (c==' '||c=='\t'||c=='\n'||c=='\r')
                {
                    token = new Token(Token_Type.ZHIBIAOFU, "制表符");
                }
                else if (c == ',')
                {			//逗号
                    //需要添加实现代码
                    token = new Token(Token_Type.COMMA, ",");
                }
                else if (c == ';')
                {			//分号
                    //需要添加实现代码
                    token = new Token(Token_Type.SEMICO, ";");
                }
                else if (c == '(')
                {			//左括号
                    //需要添加实现代码
                    token = new Token(Token_Type.L_BRACKET, "(");
                }
                else if (c == ')')
                {			//右括号
                    //需要添加实现代码
                    token = new Token(Token_Type.R_BRACKET, ")");
                }
                else if (c == '-')
                {			//减号
                    //需要添加实现代码
                    token = new Token(Token_Type.MINUS, "-");
                }
                else if (c == '/')
                {	//除号
                    //需要添加实现代码
                    token = new Token(Token_Type.DIV, "/");
                }
                else if (c == '*')
                {		//当前输入字符是 *,说明已读出乘号或遇到乘方算符的首字母
                    //需要添加实现代码
                    for(; ; )
                    {
                        c = getChar(sr);//读取新字符
                        if (c=='*')
                        {	//读入字符仍是字母/数字,说明还在标识符中                            
                            token = new Token(Token_Type.POWER, "**");
                        }
                        else
                        {
                            token = new Token(Token_Type.MUL, "*");
                        }
                    }
                }
                else if (char.IsLetter(c))
                {	//当前输入字符是字母,说明可能遇到了标识符的首字母
                    string buf = ""; //初始化临时串
                    buf = buf + char.ToUpper(c);//首字母转换为大写,存入临时串

                    //循环读取后续字符
                    for (; ;)
                    {
                        c = getChar(sr);//读取新字符
                        if (char.IsLetterOrDigit(c))
                        {	//读入字符仍是字母/数字,说明还在标识符中                            
                            buf = buf + char.ToUpper(c);//读入字符连接到临时串
                        }
                        else         //读入字符不再是字母/数字,说明标识符已读完,并且多读了一个不属于标识符的输入
                            break;
                    }
                    ungetChar(sr);	//将多读的字符退回输入流

                    token = IsKeyWords(buf);
                    //token = new Token(Token_Type.ID, buf);

                }
                else if (char.IsDigit(c))
                {	//当前输入字符是数字,说明遇到了数值常量的首个数字字母
                    //需要添加实现代码
                    string buf = c.ToString(); //初始化临时串
                    for(; ; )
                    {
                        c = getChar(sr);//读取新字符
                        if (char.IsDigit(c))
                        {	//读入字符仍是字母/数字,说明还在标识符中   
                            
                            buf = buf + c;//读入字符连接到临时串
                        }else if (c == '.')
                        {
                            c = getChar(sr);
                            if (c == '.')
                            {
                                token = ErrorToken;
                            }
                            else
                            {
                                buf = buf + c;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                    ungetChar(sr);  //将多读的字符退回输入流
                    token = new Token(Token_Type.CONST_ID, buf);
                }
                else
                    token = ErrorToken;

                writeToken(token);//输出单词

            }
            writeToken(token);//输出结束记号
            sr.Close();//关闭文件

            Console.ReadLine();
        }
    }
}

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值