【问题标题】:Facing an issue while making a lexical analyzer for C++ code in Python在 Python 中为 C++ 代码制作词法分析器时遇到问题
【发布时间】:2021-01-08 14:58:08
【问题描述】:

我正在尝试从头开始为 C++ 代码制作一个非常简单的词法分析器(Tokenizer),而不使用 PLY 或任何其他库。

到目前为止我做过的事情:

  • 在字典中定义关键字、运算符。
  • 为注释、文字等定义了正则表达式。

我的困惑:

问题一:

现在我正在尝试创建一个函数check_line(line),它将使用一行代码并在字典中返回标记。例如:

check_line('int main()')

输出应该是:

Tokens = {'Keyword':'int', 'Keyword':'main', 'Opening parenthesis':'(','Closing Parenthesis':')'}

但我得到的输出是:

Tokens = {'Keyword':'main', 'Keyword':'main', 'Opening parenthesis':'(','Closing Parenthesis':')'}

因为 main 在这里覆盖了 int。

有没有办法解决这样的问题?

问题2:

当我在函数中传递check_line('int main()') 时,程序与main 不匹配,因为这里我们有括号。我该如何解决这个问题。

我正在粘贴我到目前为止编写的代码,请看一下并告诉我你的想法。

import re

# Keywords
keywords = ['const','float','int','struct','break',
            'continue','else','for','switch','void',
            'case','enum','sizeof','typedef','char',
            'do','if','return','union','while','new',
            'public','class','friend','main']


# Regular Expression for Identifiers
re_id = '^[_]?[a-z]*[A-Z]([a-z]*[A-Z]*[0-9]+)'

# Regular Expression for Literals
re_int_lit = '^[+-]?[0-9]+'
re_float_lit = '^[+-]?([0-9]*)\.[0-9]+'
re_string_lit = '^"[a-zA-Z0-9_ ]+"$'

# Regular expression of Comments
re_singleline_comment = '^//[a-zA-Z0-9 ]*'
re_multiline_comment = '^/\\*(.*?)\\*/'

operators = {'=':'Assignment','-':'Subtraction',
             '+':'Addition','*':'Multiplication',
            '/':'Division','++':'increment',
            '--':'Decrement','||':'OR', '&&':'AND',
            '<<':'Cout operator','>>':'Cin Operator',
            ';':'End of statement'}

io = {'cin':'User Input',
      'cout':'User Output'} 

brackets = {'[':'Open Square',']':'Close Square',
           '{':'Open Curly','}':'Close Curly',
           '(':'Open Small',')':'Close Small'}


# Function

def check_line(line):
    tokens = {}
    words = line.split(' ')
    for word in words:
        if word in operators.keys():
            tokens['Operator ' + word] = word

        if word in keywords:
            tokens['Keywords'] = word
        
        if re.match(re_singleline_comment,word):
            break
       
    return tokens


check_line('int main()')

输出:

{'Keywords': 'main'}

输出应该是:

Tokens = {'Keyword':'int', 'Keyword':'main', 'Opening parenthesis':'(','Closing Parenthesis':')'}

PS:我还没有完成条件,只是想先解决这个问题。

【问题讨论】:

  • 您不能使用 split - 如果标记之间没有空格,例如 main(),则标记器将失败。您需要一次构建一个字符的令牌。在编写任何代码之前给自己画一个状态图或铁路图。如果你搜索lexical analysis state diagram,有很多例子说明如何做到这一点

标签: python lexical-analysis


【解决方案1】:

字典对于这个函数来说是一个非常糟糕的数据结构选择,因为字典的本质是每个键都与一个对应的值相关联。

分词器应该返回的是完全不同的:一个有序的令牌对象流。在一个简单的实现中,这可能是一个元组列表,但对于任何不平凡的应用程序,您很快就会发现:

  1. 标记不仅仅是句法类型和字符串。有很多重要的辅助信息,最值得注意的是输入流中令牌的位置(用于错误消息)。

  2. 代币几乎总是按顺序消耗的,一次生产多个代币并没有什么特别的优势。在 Python 中,生成器是一种更自然的生成标记流的方式。如果创建标记列表很有用(例如,实现回溯解析器),那么逐行工作就没有意义了,因为换行符在 C++ 中通常是不相关的。

正如评论中所指出的,C++ 标记并不总是由空格分隔,这在您的示例输入中很明显。 (main() 是三个不包含单个空格字符的标记。)将程序文本拆分为标记流的最佳方法是在当前输入光标处重复匹配标记模式,返回最长匹配,然后将输入光标移到匹配。

【讨论】:

  • 非常感谢,这很有帮助!
猜你喜欢
  • 1970-01-01
  • 2019-12-22
  • 1970-01-01
  • 1970-01-01
  • 2022-11-16
  • 2013-11-06
  • 1970-01-01
  • 2021-10-17
  • 1970-01-01
相关资源
最近更新 更多