编译原理上机——函数绘图语言(二):词法分析器

相关篇目

编译原理上机——函数绘图语言(一)
编译原理上机——函数绘图语言(三):语法分析器
编译原理上机——函数绘图语言(四):语义分析器
编译原理上机——函数绘图语言(五):编译器与解释器
完整代码
Gitee开源代码

词法分析器

生成符号表

这是一个表驱动型词法分析器,符号表将会被保存在文件TOKEN.npy中.

# -*- coding: utf-8 -*-
"""
Created on Mon Nov 23 20:05:45 2020

@author: FishPotatoChen

Copyright (c) 2020 FishPotatoChen All rights reserved.
"""

import numpy as np
import math

TOKEN = {
    # 常量
    'PI': {'TYPE': 'CONST_ID', 'VALUE': math.pi, 'FUNCTION': None},
    'E': {'TYPE': 'CONST_ID', 'VALUE': math.e, 'FUNCTION': None},
    # 变量
    'T': {'TYPE': 'SYMBOL', 'VALUE': None, 'FUNCTION': None},
    # 函数
    'SIN': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': math.sin},
    'COS': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': math.cos},
    'TAN': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': math.tan},
    # log(x,a)如果不指定a,则默认以e为基数
    'LOG': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': math.log},
    'EXP': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': math.exp},
    'SQRT': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': math.sqrt},
    # 保留字
    'ORIGIN': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
    'SCALE': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
    'ROT': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
    'IS': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
    'FOR': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
    'FROM': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
    'TO': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
    'STEP': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
    'DRAW': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
    # 运算符
    '+': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
    '-': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
    '*': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
    '/': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
    '**': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
    # 记号
    '(': {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None},
    ')': {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None},
    ',': {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None},
    # 结束符
    ';': {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None},
    # 空
    '': {'TYPE': 'EMPTY', 'VALUE': None, 'FUNCTION': None},
    # 数字
    '0': {'TYPE': 'NUMBER', 'VALUE': 0.0, 'FUNCTION': None},
    '1': {'TYPE': 'NUMBER', 'VALUE': 1.0, 'FUNCTION': None},
    '2': {'TYPE': 'NUMBER', 'VALUE': 2.0, 'FUNCTION': None},
    '3': {'TYPE': 'NUMBER', 'VALUE': 3.0, 'FUNCTION': None},
    '4': {'TYPE': 'NUMBER', 'VALUE': 4.0, 'FUNCTION': None},
    '5': {'TYPE': 'NUMBER', 'VALUE': 5.0, 'FUNCTION': None},
    '6': {'TYPE': 'NUMBER', 'VALUE': 6.0, 'FUNCTION': None},
    '7': {'TYPE': 'NUMBER', 'VALUE': 7.0, 'FUNCTION': None},
    '8': {'TYPE': 'NUMBER', 'VALUE': 8.0, 'FUNCTION': None},
    '9': {'TYPE': 'NUMBER', 'VALUE': 9.0, 'FUNCTION': None},
    '.': {'TYPE': 'NUMBER', 'VALUE': None, 'FUNCTION': None},
}

np.save('TOKEN.npy', TOKEN)

词法分析器主体

文件名为lexer.py

# -*- coding: utf-8 -*-
"""
Created on Mon Nov 23 20:05:45 2020

@author: FishPotatoChen

Copyright (c) 2020 FishPotatoChen All rights reserved.
"""

# 词法分析器

import math
import re
import numpy as np


class Lexer:
    def __init__(self):
        # 从文件中读取记号表
        self.TOKEN = np.load('TOKEN.npy', allow_pickle=True).item()

    def getToken(self, sentence):
        if sentence:
            tokens = sentence.split()
            for token in tokens:
                try:
                    # No.0
                    # 首先识别直接可以识别的记号
                    # 正规式为ORIGIN|SCALE|ROT|IS|FOR|FROM|TO|STEP|DRAW|ε
                    self.output_token(token)
                    # No.0  识别结束
                except:
                    # 找不到就进入更高级的DFA中识别
                    self.argument_lexer(token)
            self.output_token(';')

    # 构造更为复杂、高级的、多种类的识别表达式
    def argument_lexer(self, argument):
        # 扫描位置
        i = 0
        # 字符串长度
        length = len(argument)
        while(i < length):
            # 临时字符串,即缓冲区
            temp = ''
            if argument[i] in ['P', 'S', 'C', 'L', 'E', 'T', '*']:
                # No.1
                # 识别"*"还是"**"的过程是一个上下文有关文法
                if argument[i] == '*':
                    i += 1
                    if i >= length:
                    	self.output_token(argument[i])
                        break
                    elif argument[i] == '*':
                        self.output_token('**')
                    else:
                        i -= 1
                        self.output_token(argument[i])
                # No.1  识别结束
                else:
                    # No.2
                    # DFA判断全为字母的字符串
                    # 正规式为PI|E|T|SIN|COS|TAN|LOG|EXP|SQRT
                    temp = re.findall(r"[A-Z]+", argument[i:])[0]
                    # 看该串是否接受
                    self.output_token(temp)
                    i += len(temp)-1
                    if i >= length:
                        break
                    # No.2  识别结束
            elif argument[i] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.']:
                # No.3
                # 识别数字
                if argument[i] == '.':
                    # 识别开头为"."的数字
                    # 正规式为.[0-9]+
                    # 如:.52=>0.52
                    i += 1
                    temp = re.findall(r"\d+", argument[i:])[0]
                    i += len(temp)-1
                    temp = '0.' + temp
                    self.output_token(temp, False)
                else:
                    # 识别一般数字
                    # 正规式为[0-9]+.?[0-9]*
                    # 如:5.52=>5.52;12=>12
                    temp = re.findall(r"\d+\.?\d*", argument[i:])[0]
                    i += len(temp)-1
                    self.output_token(temp, False)
                if i >= length:
                    break
                # No.3   识别结束
            else:
                # No.4
                # 识别其他字符
                # 正规式为+|-|/|(|)|,|ε
                self.output_token(argument[i])
            i += 1

    # 输出函数
    # 因为解释器可以不用输出至屏幕,但是题目要求输出至屏幕
    # 所以特别写了一个函数用于输出,便于接下来的语法分析器调用文法分析器
    # 当输出不为屏幕时,将输出嵌入代码会变得不好更改
    # 如果写成独立函数,直接更改输出函数即可
    def output_token(self, token, NotNumber=True):
        if NotNumber:
            print(token, self.TOKEN[token])
        else:
            tempdic = {token: {'TYPE': 'NUMBER', 'VALUE': float(token), 'FUNCTION': None}}
            print(token, tempdic[token])

扫描器

文件名为scanner.py

# -*- coding: utf-8 -*-
"""
Created on Mon Nov 23 20:05:45 2020

@author: FishPotatoChen

Copyright (c) 2020 FishPotatoChen All rights reserved.
"""

# 输入处理器
import re
import lexer


class Scanner():
    def __init__(self, path="test.txt"):
        # 读入文件位置
        self.path = path
        # 设置缓冲区
        self.text = ""
        with open(self.path, "r") as f:
            lines = f.readlines()
            for line in lines:
                # 将文件中注释去掉
                self.text = self.text + \
                    line.split("//")[0].split("--")[0].split("\n")[0]
        self.text = self.text.upper().strip()
        self.lexer = lexer.Lexer()

    def analyze(self):
        sentences = re.split("(;)", self.text)
        # No.0
        # 识别
        # E->E;|ε
        # 用于记录状态机状态,当state == True时,意味着可以读入一个E,当state == False时,意味着可以读入一个;
        state = True
        for sentence in sentences:
            if state and sentence != ";":
                state = False
                self.lexer.getToken(sentence)
            elif sentence == ";":
                state = True
            else:
                raise SyntaxError()
        if state:
            raise SyntaxError()
        # No.0   识别结束

主函数

文件名为main.py

# -*- coding: utf-8 -*-
"""
Created on Mon Nov 23 20:05:45 2020

@author: FishPotatoChen

Copyright (c) 2020 FishPotatoChen All rights reserved.
"""

import scanner

if __name__ == "__main__":
    # print("输入\t类型\t\t\t值\t\t函数")
    scan = scanner.Scanner()
    scan.analyze()

测试

测试文件

文件名为test.txt

for t from 0.5.6.7 to 2*E step e/10 draw (5*T *T *T * cos( T ),sin(T));;;;origin is (100,100); //ksdjfksdjkl
//dsfsdfdsf
origin is --ksdjfksdjkl
(0,0); 
origin is //kssdfj
 (10,10);
origin is (0,0); --ksdjfksdjkl
origin is (10,10); //kssdfj
ROT is E/4;
ROT is pi ** 4;
ROT is pi /4*5;
ROT is sin( 4.5)*cos(3.5);
ROT is pi/4;


输出结果

FOR {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
T {'TYPE': 'SYMBOL', 'VALUE': None, 'FUNCTION': None}
FROM {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
0.5 {'TYPE': 'NUMBER', 'VALUE': 0.5, 'FUNCTION': None}
0.6 {'TYPE': 'NUMBER', 'VALUE': 0.6, 'FUNCTION': None}
0.7 {'TYPE': 'NUMBER', 'VALUE': 0.7, 'FUNCTION': None}
TO {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
2 {'TYPE': 'NUMBER', 'VALUE': 2.0, 'FUNCTION': None}
* {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
E {'TYPE': 'CONST_ID', 'VALUE': 2.718281828459045, 'FUNCTION': None}
STEP {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
E {'TYPE': 'CONST_ID', 'VALUE': 2.718281828459045, 'FUNCTION': None}
/ {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
10 {'TYPE': 'NUMBER', 'VALUE': 10.0, 'FUNCTION': None}
DRAW {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
5 {'TYPE': 'NUMBER', 'VALUE': 5.0, 'FUNCTION': None}
* {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
T {'TYPE': 'SYMBOL', 'VALUE': None, 'FUNCTION': None}
* {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
T {'TYPE': 'SYMBOL', 'VALUE': None, 'FUNCTION': None}
* {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
T {'TYPE': 'SYMBOL', 'VALUE': None, 'FUNCTION': None}
* {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
COS {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': <built-in function cos>}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
T {'TYPE': 'SYMBOL', 'VALUE': None, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
, {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
SIN {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': <built-in function sin>}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
T {'TYPE': 'SYMBOL', 'VALUE': None, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ORIGIN {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
100 {'TYPE': 'NUMBER', 'VALUE': 100.0, 'FUNCTION': None}
, {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
100 {'TYPE': 'NUMBER', 'VALUE': 100.0, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ORIGIN {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
0 {'TYPE': 'NUMBER', 'VALUE': 0.0, 'FUNCTION': None}
, {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
0 {'TYPE': 'NUMBER', 'VALUE': 0.0, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ORIGIN {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
10 {'TYPE': 'NUMBER', 'VALUE': 10.0, 'FUNCTION': None}
, {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
10 {'TYPE': 'NUMBER', 'VALUE': 10.0, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ORIGIN {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
0 {'TYPE': 'NUMBER', 'VALUE': 0.0, 'FUNCTION': None}
, {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
0 {'TYPE': 'NUMBER', 'VALUE': 0.0, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ORIGIN {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
10 {'TYPE': 'NUMBER', 'VALUE': 10.0, 'FUNCTION': None}
, {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
10 {'TYPE': 'NUMBER', 'VALUE': 10.0, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ROT {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
E {'TYPE': 'CONST_ID', 'VALUE': 2.718281828459045, 'FUNCTION': None}
/ {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
4 {'TYPE': 'NUMBER', 'VALUE': 4.0, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ROT {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
PI {'TYPE': 'CONST_ID', 'VALUE': 3.141592653589793, 'FUNCTION': None}
** {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
4 {'TYPE': 'NUMBER', 'VALUE': 4.0, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ROT {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
PI {'TYPE': 'CONST_ID', 'VALUE': 3.141592653589793, 'FUNCTION': None}
/ {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
4 {'TYPE': 'NUMBER', 'VALUE': 4.0, 'FUNCTION': None}
* {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
5 {'TYPE': 'NUMBER', 'VALUE': 5.0, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ROT {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
SIN {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': <built-in function sin>}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
4.5 {'TYPE': 'NUMBER', 'VALUE': 4.5, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
* {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
COS {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': <built-in function cos>}
( {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
3.5 {'TYPE': 'NUMBER', 'VALUE': 3.5, 'FUNCTION': None}
) {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
ROT {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
IS {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None}
PI {'TYPE': 'CONST_ID', 'VALUE': 3.141592653589793, 'FUNCTION': None}
/ {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None}
4 {'TYPE': 'NUMBER', 'VALUE': 4.0, 'FUNCTION': None}
; {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FishPotatoChen

谢谢您的支持,我会更努力的~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值