Fur*_*dhi 3 python programming-languages lexer
我不知道如何/从哪里开始。我应该使用 python,更具体地说,使用 ply 库。到目前为止,我所做的只是创建一个将成为该语言一部分的标记列表。该列表如下:
tokens = (
# OPERATORS #
'PLUS' , # +
'MINUS' , # -
'MULTIPLY', # *
'DIVIDE', # /
'MODULO', # %
'NOT', # ~
'EQUALS', # =
# COMPARATORS #
'LT', # <
'GT', # >
'LTE', # <=
'GTE', # >=
'DOUBLEEQUAL', # ==
'NE', # #
'AND', # &
'OR', # |
# CONDITIONS AND LOOPS #
'IF', # if
'ELSE', # else
'ELSEIF', # elseif
'WHILE', # while
'FOR', # for
# 'DOWHILE', # haven't thought about this yet
# BRACKETS #
'LPAREN', # (
'RPAREN', # )
'LBRACE', # [
'RBRACE', # ]
'BLOCKSTART', # {
'BLOCKEND', # }
# IDENTIFIERS #
'INTEGER', # int
'DOUBLE', # dbl
'STRING', # str
'CHAR', # char
'SEMICOLON', # ;
'DOT', # .
'COMMA', # ,
'QUOTES', # '
'DOUBLEQUOTES', # "
'COMMENTLINE', # --
'RETURN', # return
)
Run Code Online (Sandbox Code Playgroud)
显然我还有很长的路要走,因为我还需要编写一个解析器和一个解释器。
我有几个问题:
我尝试过在谷歌上搜索有关编写新编程语言的内容,但尚未找到任何令人满意的内容
ama*_*anb 13
如何使用层库?
假设您已经安装了 Ply,您应该从探索Ply 官方网站上的教程开始。它们写得很好并且很容易理解。
这是一个好的开始吗?如果是的话,我该怎么办?
Ply 首先需要令牌定义。你已经这么做了。然而,当你的词法分析器必须区分像“forget”这样的字符串和像 这样的保留关键字时,复杂性就会增加for。该库为变量优先级提供了良好的支持,以解决语法歧义。这就像将优先级定义为元组一样简单:
precedence = (
('left', 'STRING', 'KEYWORD'),
('left', 'MULTIPLY', 'DIVIDE')
)
Run Code Online (Sandbox Code Playgroud)
不过,我建议您在深入研究 Ply 中的表达式和优先级等更高级的功能之前,应该阅读有关词法分析器和 yacc的更多内容。首先,您应该构建一个简单的数字词法分析器,以成功解析整数、运算符和括号符号。我减少了令牌定义以适应此目的。下面的例子是根据官方教程修改的。
库导入和令牌定义:
import ply.lex as lex #library import
# List of token names. This is always required
tokens = [
# OPERATORS #
'PLUS' , # +
'MINUS' , # -
'MULTIPLY', # *
'DIVIDE', # /
'MODULO', # %
'NOT', # ~
'EQUALS', # =
# COMPARATORS #
'LT', # <
'GT', # >
'LTE', # <=
'GTE', # >=
'DOUBLEEQUAL', # ==
'NE', # !=
'AND', # &
'OR' , # |
# BRACKETS #
'LPAREN', # (
'RPAREN', # )
'LBRACE', # [
'RBRACE', # ]
'BLOCKSTART', # {
'BLOCKEND', # }
# DATA TYPES#
'INTEGER', # int
'FLOAT', # dbl
'COMMENT', # --
]
Run Code Online (Sandbox Code Playgroud)为简单标记定义正则表达式规则:Ply 使用rePython 库来查找用于标记化的正则表达式匹配。每个标记都需要一个正则表达式定义。我们首先定义简单标记的正则表达式定义。每个规则声明都以特殊前缀开头t_,表明它定义了一个标记。
# Regular expression rules for simple tokens
t_PLUS = r'\+'
t_MINUS = r'-'
t_MULTIPLY = r'\*'
t_DIVIDE = r'/'
t_MODULO = r'%'
t_LPAREN = r'\('
t_RPAREN = r'\)'
t_LBRACE = r'\['
t_RBRACE = r'\]'
t_BLOCKSTART = r'\{'
t_BLOCKEND = r'\}'
t_NOT = r'\~'
t_EQUALS = r'\='
t_GT = r'\>'
t_LT = r'\<'
t_LTE = r'\<\='
t_GTE = r'\>\='
t_DOUBLEEQUAL = r'\=\='
t_NE = r'\!\='
t_AND = r'\&'
t_OR = r'\|'
t_COMMENT = r'\#.*'
t_ignore = ' \t' ignore spaces and tabs
Run Code Online (Sandbox Code Playgroud)为更复杂的标记(例如 int、float 和换行符等数据类型)定义正则表达式规则,以跟踪行号。您会注意到这些定义与上面的非常相似。
#Rules for INTEGER and FLOAT tokens
def t_INTEGER(t):
r'\d+'
t.value = int(t.value)
return t
def t_FLOAT(t):
r'(\d*\.\d+)|(\d+\.\d*)'
t.value = float(t.value)
return t
# Define a rule so we can track line numbers
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
Run Code Online (Sandbox Code Playgroud)添加一些对无效字符的错误处理:
# Error handling rule
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
Run Code Online (Sandbox Code Playgroud)构建词法分析器:
lexer = lex.lex()
Run Code Online (Sandbox Code Playgroud)使用一些输入数据测试词法分析器,标记并打印标记:
data = '''
[25/(3*40) + {300-20} -16.5]
{(300-250)<(400-500)}
20 & 30 | 50
# This is a comment
'''
# Give the lexer some input
lexer.input(data)
# Tokenize
for tok in lexer:
print(tok)
Run Code Online (Sandbox Code Playgroud)您可以将此示例代码添加到 Python 脚本文件(例如)new_lexer.py并像 一样运行它python new_lexer.py。您应该得到以下输出。请注意,输入数据由 newline( '\n') 字符组成,这些字符在输出中被成功忽略。
#Output
LexToken(LBRACE,'[',2,1)
LexToken(INTEGER,25,2,2)
LexToken(DIVIDE,'/',2,4)
LexToken(LPAREN,'(',2,5)
LexToken(INTEGER,3,2,6)
LexToken(MULTIPLY,'*',2,7)
LexToken(INTEGER,40,2,8)
LexToken(RPAREN,')',2,10)
LexToken(PLUS,'+',2,12)
LexToken(BLOCKSTART,'{',2,14)
LexToken(INTEGER,300,2,15)
LexToken(MINUS,'-',2,18)
LexToken(INTEGER,20,2,19)
LexToken(BLOCKEND,'}',2,21)
LexToken(MINUS,'-',2,23)
LexToken(INTEGER,16,2,24)
LexToken(FLOAT,0.5,2,26)
LexToken(RBRACE,']',2,28)
LexToken(BLOCKSTART,'{',3,30)
LexToken(LPAREN,'(',3,31)
LexToken(INTEGER,300,3,32)
LexToken(MINUS,'-',3,35)
LexToken(INTEGER,250,3,36)
LexToken(RPAREN,')',3,39)
LexToken(LT,'<',3,40)
LexToken(LPAREN,'(',3,41)
LexToken(INTEGER,400,3,42)
LexToken(MINUS,'-',3,45)
LexToken(INTEGER,500,3,46)
LexToken(RPAREN,')',3,49)
LexToken(BLOCKEND,'}',3,50)
LexToken(INTEGER,20,4,52)
LexToken(AND,'&',4,55)
LexToken(INTEGER,30,4,57)
LexToken(OR,'|',4,60)
LexToken(INTEGER,50,4,62)
LexToken(COMMENT,'# This is a comment',5,65)
Run Code Online (Sandbox Code Playgroud)
您还可以使用许多其他功能。例如,可以使用 启用调试lex.lex(debug=True)。官方教程提供了有关这些功能的更详细信息。
我希望这有助于您入门。您可以进一步扩展代码以包含保留关键字,例如if、while字符串标识STRING、 字符标识CHAR。本教程介绍了通过定义键值字典映射来实现保留字,如下所示:
reserved = {
'if' : 'IF',
'then' : 'THEN',
'else' : 'ELSE',
'while' : 'WHILE',
...
}
Run Code Online (Sandbox Code Playgroud)
type通过将保留标记定义为'ID'并包括reserved字典值来进一步扩展标记列表:tokens.append('ID')和tokens = tokens + list(reserved.values())。t_ID然后,添加上面的定义。
有什么资源可以帮助我解决这个问题吗?
有许多资源可用于了解词法分析器、解析器和编译器。您应该从一本涵盖理论和实施的好书开始。有许多书籍涵盖了这些主题。我喜欢这个。这是另一个可能有帮助的资源。如果您想探索类似的 Python 库或资源,这个答案可能会有所帮助。
| 归档时间: |
|
| 查看次数: |
12895 次 |
| 最近记录: |