我不知道如何/从哪里开始。我应该使用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
)
显然,我还有很长的路要走,因为我还需要编写一个解析器和一个解释器。
我有几个问题:
我已经尝试过使用谷歌搜索技术来编写新的编程语言,但还没有找到令人满意的方法
答案 0 :(得分:1)
如何使用层库?
假设您已经安装了Ply,则应该从浏览official Ply website上的教程开始。它们写得很好并且易于遵循。
这是一个好的开始吗?如果是的话,我该怎么做?
Ply需要以令牌定义开头。您已经完成了。但是,当您的词法分析器必须区分诸如“ forget”之类的字符串与诸如for
之类的保留关键字时,复杂性会增加。该库为变量优先级提供了良好的支持,以解决语法歧义。这就像定义元组的优先级一样容易:
precedence = (
('left', 'STRING', 'KEYWORD'),
('left', 'MULTIPLY', 'DIVIDE')
)
但是,我建议您在深入了解Ply中的表达式和优先级等更高级的功能之前,应该先阅读有关lexers and 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', # --
]
为简单标记定义正则表达式规则:Ply使用re
Python库查找用于标记化的正则表达式匹配项。每个令牌都需要一个正则表达式定义。我们首先为简单标记定义正则表达式定义。每个规则声明都以特殊的前缀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
为更复杂的令牌定义正则表达式规则,例如数据类型(例如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)
为无效字符添加一些错误处理:
# Error handling rule
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
构建词法分析器:
lexer = lex.lex()
使用一些输入数据测试词法分析器,标记化并打印标记:
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)
您可以将此示例代码添加到new_lexer.py
之类的Python脚本文件中,然后像python new_lexer.py
那样运行。您应该获得以下输出。请注意,输入数据由换行符('\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)
您还可以使用许多其他功能。例如,可以使用lex.lex(debug=True)
启用调试。官方教程提供了有关这些功能的更多详细信息。
我希望这有助于您入门。您可以进一步扩展代码,使其包含诸如if
,while
之类的保留关键字,并以STRING
标识字符串,以CHAR
标识字符。这些教程通过定义如下的键值字典映射来介绍保留字的实现:
reserved = {
'if' : 'IF',
'then' : 'THEN',
'else' : 'ELSE',
'while' : 'WHILE',
...
}
通过将保留令牌type
定义为'ID'
并包括reserved
字典值:tokens.append('ID')
和tokens = tokens + list(reserved.values())
,进一步扩展令牌列表。然后,如上所述为t_ID
添加一个定义。
我有什么资源可以帮助我解决这个问题。
有很多资源可用于学习词法分析器,解析器和编译器。您应该从一本涵盖理论和实现的好书开始。有很多书籍涵盖了这些主题。我喜欢这个one。 Here's可能会有帮助的另一资源。如果您想探索类似的Python库或资源,此SO answer可能会有所帮助。