《编译原理》扫描器类的设计

扫描器类的设计

【问题描述】

    熟悉并实现一个简单的扫描器,设计扫描器的自动机;设计翻译、生成Token的算法;编写代码并上机调试运行通过。

    1. 扫描器可识别的单词包括:关键字、界符、标识符和常数(常数包括如:123  123.567  0.567   12.34e+23 ......);

      1. 要求常整数输出按十进制输出(测试数据中只有16进制与10进制整数),浮点数考虑到精度问题按输入格式输出(测试数据只有10进制浮点数)。同时使用科学计数法的数字都是浮点数。为降低难度,样例3给出一种边界情况供大家调试。

      2. 在面对诸如"a+++++b"以及"a+++b"这种丧心病狂的输入时,界符匹配按照从左向右贪心匹配最长界符的策略进行匹配。

    2. 判断字符常量及字符串常量单词,将字符和字符串常量分别保存进单独的常量表CT、ST。例如’a’、”OK”;同时字符串与字符常量均不考虑转义字符("\"和带"\"的都不考虑)。

    3. 可以识别简单的词法错误主要形式为’sdddd’、1.sdasf等,尚未定义的单词等。

    其中关键字表、界符表、标识符表、常整数表、常实数表、字符表、字符串表如下:(表中除关键词与界符表的表都可以接着编号继续扩展)

【输入形式】一行带空格的输入。其中关于数字,对于整型保证仅需考虑10进制与16进制数据,对于浮点型保证仅需考虑10进制数据。

【输出形式】

  1. 相应单词的Token序列;

  2. 标识符表,整数表,实数表,字符表,字符串表

  3. 如果错误则输出"ERROR"。

【样例输入】

样例1输入:
120+10.3*12.3e-1;

样例2输入:
a="xyz";

样例3输入:
int a=12.1; float b=15e2, c=0x15e2;

样例4输入:
int a='label';

【样例输出】

样例1输出:
Token :(C1 1)(P 8)(C2 1)(P 9)(C2 2)(P 13)
I :
C1 :120
C2 :10.3 12.3e-1
CT :
ST :

样例2输出:
Token :(I 1)(P 11)(ST 1)(P 13)
I :a
C1 :
C2 :
CT :
ST :xyz

样例3输出:
Token :(K 1)(I 1)(P 11)(C2 1)(P 13)(K 4)(I 2)(P 11)(C2 2)(P 12)(I 3)(P 11)(C1 1)(P 13)
I :a b c 
C1 :5602 
C2 :12.1 15e2 
CT :
ST :

样例4输出:
ERROR

【样例说明】

    样例3中,0x15e2看起来是一个使用科学计数法的浮点数,但实际上他是一个16进制整型。其中e并不代表指数而是代表十进制下的数字14。这也是为什么16进制下不能使用e来进行科学计数的原因。扩展阅读:Floating-point literal - cppreference.com c - Why does hexadecimal floating point need to have a specified exponent? - Stack Overflow 

【评分标准】

import re
import sys

K = ['','int','void','break','float','while','do','struct','const','case','for','return','if','default','else']
P = ['','-','/','(',')','==','<=','<','+','*','>','=',',',';','++','{','}']
I = ['']
C1 = ['']
C2 = ['']
CT = ['']
ST = ['']
P_first = ['=','<','+']
sep = [' ','\n','\t',"'",'"']

def in_p_sep(ch):
    return ch in P or ch in sep

def print_error():
    print("ERROR")

def is_C1(str1):
    if re.match(r'^[0-9]+$',str1):
        return 1
    elif re.match(r'^0x[0-9a-zA-Z]+$',str1):
        return 2
    else:
        return 0

def is_C2(str1):
    return bool(re.match(r'^[0-9]+(?:\.[0-9]+)?(?:e[+-]?[0-9]+)?$', str1))

def is_CT(str1):
    return bool(re.match(r"^'[a-zA-Z0-9]$",str1))

def is_ST(str1):
    return bool(re.match(r'^\".*$',str1))

def is_I(str1):
    return bool(re.match(r'^[a-zA-Z_]\w*$',str1))

def judge(str1, Token):
    if str1 in K:
        num = K.index(str1)
        Token += f'(K {num})'
    elif str1 in C1:
        num = C1.index(str1)
        Token += f'(C1 {num})'
    elif str1 in C2:
        num = C2.index(str1)
        Token += f'(C2 {num})'
    elif str1 in CT:
        num = CT.index(str1)
        Token += f'(CT {num})'
    elif str1 in ST:
        num = ST.index(str1)
        Token += f'(ST {num})'
    elif str1 in P:
        num = P.index(str1)
        Token += f'(P {num})'
    else:
        if is_C1(str1) == 1:
            C1.append(str1)
            num = C1.index(str1)
            Token += f'(C1 {num})'
        elif is_C1(str1) == 2:
            C1.append(str(int(str1, 16)))
            num = C1.index(str(int(str1, 16)))
            Token += f'(C1 {num})'
        elif is_C2(str1):
            C2.append(str1)
            num = C2.index(str1)
            Token += f'(C2 {num})'
        elif is_CT(str1):
            CT.append(str1[1:])
            num = CT.index(str1[1:])
            Token += f'(CT {num})'
        elif is_ST(str1):
            ST.append(str1[1:])
            num = ST.index(str1[1:])
            Token += f'(ST {num})'
        elif is_I(str1):
            I.append(str1)
            num = I.index(str1)
            Token += f'(I {num})'
        else:
            print_error()
            sys.exit() 
    return Token

def main():
    Token = "Token :"
    a = str(input())
    flag, flag2, flag3 = 0, 0, 0
    str1, str2 = "", ""
    
    for i in a:
        if in_p_sep(i):
            if i == '-' and flag2 == 2:
               str1 += i
               continue
            elif i in sep:
                if i in ["'", '"']:
                    flag = 1 if flag == 0 else 0
            if bool(str1) and flag == 0:
                Token = judge(str1, Token)
                str1 = ""
                flag2 = 0
            if flag == 0:
                if i in P and flag3 == 1:
                    if not judge(str2+i, Token):
                        Token = judge(str2, Token)
                        Token = judge(i, Token)
                    else:
                        Token = judge(str2+i, Token)
                    str2 = ""
                    flag3 = 0
                elif i in P_first and flag3 == 0:
                    flag3 = 1
                    str2 += i
                elif i in P and i not in P_first and flag3 == 0:
                    Token = judge(i, Token)    
            else:
                str1 += i 
        else:
            if i == 'e' and flag2 != 1:
                flag2 = 2
            elif str1 == '0x':
                flag2 = 1
            elif flag == 1:
                flag = 4
            elif flag == 2:
                flag = 4
            elif flag == 2 and i != 'e':
                flag == 0
            if flag3 == 1:
                Token = judge(str2, Token)
                str2 = ""
                flag3 = 0
            str1 += i
    if bool(str1):
        Token = judge(str1, Token)
        str1 = ""
    print(Token)
    print("I :", end="")
    for keyword in I[1:]:
        print(keyword, end=" ")
    print("\nC1 :", end="")
    for keyword in C1[1:]:
        print(keyword, end=" ")
    print("\nC2 :", end="")
    for keyword in C2[1:]:
        print(keyword, end=" ")
    print("\nCT :", end="")
    for keyword in CT[1:]:
        print(keyword, end=" ")
    print("\nST :", end="")
    for keyword in ST[1:]:
        print(keyword, end=" ")        

if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值