アルゴリズムの動作の説明で入力ファイルを処理しようとしています。私はlexerとparserを定義するためにPythonのPLYモジュールを使用しています。私は、このファイルを正しく書くようにユーザに強いる文法を定義するという問題に遭遇しました。構文エラーでPLYを使用してファイルの構造を適用してください
ファイル
# Beginning of the first section
STATES = INITIATOR, IDLE, DONE;
INIT = INITIATOR, IDLE;
TERM = DONE;
# End of first section
# Beginning of the second section
INITIATOR
RANDOM
begin
SEND(x, NEIGHBORS);
BECOME(DONE);
end
IDLE
RECEIVE(x)
begin
SEND(x, NEIGHBORS);
BECOME(DONE);
end
# End of second section
レクサー
import ply.lex as lex
from soda.helpers import prepare_file
class Lexer(object):
keywords = (
'INIT', 'TERM', 'STATES', 'REGISTERS',
'begin', 'end',
'SEND', 'BECOME'
)
tokens = keywords + (
'NAME', 'EQUALS', 'COMMA', 'SEMICOLON',
'LPAREN', 'RPAREN'
)
# Tokens
t_EQUALS = r'='
t_COMMA = r','
t_SEMICOLON = r';'
t_STATES = r'STATES'
t_REGISTERS = r'REGISTERS'
t_INIT = r'INIT'
t_TERM = r'TERM'
t_begin = r'begin'
t_end = r'end'
t_SEND = r'SEND'
t_BECOME = r'BECOME'
t_LPAREN = r'\('
t_RPAREN = r'\)'
# Ignored characters
t_ignore = ' \t\n'
def t_NAME(self, t):
r'[a-zA-Z][a-zA-Z]*'
if t.value in self.keywords: # is this a keyword?
t.type = t.value
return t
def t_error(self, t):
print ("Illegal character {0} at line {1}".format(t.value[0], t.lineno))
t.lexer.skip(1)
def build(self, **kwargs):
self._lexer = lex.lex(module=self, **kwargs)
@prepare_file
def lexical_analysis(self, file):
print ("Started lexical analysis...")
for line in file:
try:
lex_input = line
except EOFError:
break
self._lexer.input(lex_input)
while True:
token = self._lexer.token()
if not token:
break
print (" ", token)
パーサ
import ply.yacc as yacc
from soda.helpers import prepare_file
class Parser(object):
def p_algorithm(self, p):
''' algorithm : first_section second_section'''
def p_first_section(self, p):
''' first_section : STATES EQUALS states_list SEMICOLON
| REGISTERS EQUALS register_list SEMICOLON
| INIT EQUALS init_list SEMICOLON
| TERM EQUALS term_list SEMICOLON'''
def p_states_list(self, p):
''' states_list : state_term
| states_list COMMA state_term'''
def p_state_term(self, p):
''' state_term : NAME'''
self.behavior.states.append(p[1])
def p_register_list(self, p):
''' register_list : register_term
| register_list COMMA register_term'''
def p_register_term(self, p):
''' register_term : NAME'''
self.behavior.registers.append(p[1])
def p_init_list(self, p):
''' init_list : init_term
| init_list COMMA init_term'''
def p_init_term(self, p):
''' init_term : NAME'''
self.behavior.init_states.append(p[1])
def p_term_list(self, p):
''' term_list : term_term
| term_list COMMA term_term'''
def p_term_term(self, p):
''' term_term : NAME'''
self.behavior.term_states.append(p[1])
def p_second_section(self, p):
''' second_section : NAME begin commands end'''
def p_error(self, p):
print("Syntax error in input! -> {}".format(p))
def build(self, lexer, behavior):
self.lexer = lexer
self.behavior = behavior
self.tokens = lexer.tokens
self._parser = yacc.yacc(module=self)
@prepare_file
def parsing(self, file):
for line in file:
try:
parser_input = line
print (line)
except EOFError:
break
self._parser.parse(parser_input, lexer=self.lexer._lexer)
解析結果と私は、アルゴリズムの振る舞いを持つファイルの一貫性を強制するルールを定義する方法がわかりません。 first_sectionは解析され、問題はsecond_sectionです。私の解決策は、アルゴリズムを定義しています:first_section second_sectionこれは機能しません。私はアルゴリズムのように定義しようとしました:first_section | second_sectionこれはうまくいきますが、このルールでは、第1セクションと第2セクションをファイルに切り替えることができます。
私の質問は、ユーザーが入力ファイルの一貫性を保つようにルールでそれを強制する方法です。
エラー出力
enter STATES = INITIATOR, IDLE, DONE;
Syntax error in input! -> None
INIT = INITIATOR, IDLE;
Syntax error in input! -> None
TERM = DONE;
Syntax error in input! -> None
INITIATOR
Syntax error in input! -> LexToken(NAME,'INITIATOR',1,0)
begin
Syntax error in input! -> LexToken(begin,'begin',1,0)
プログラムは、単に構文にエラーがある述べています。問題は、字句解析ではなく、定義された文法である。私はそれが入力が受け入れられるような方法でそれを定義することができますが、例えばユーザーはfirst_section
をsecond_section
に切り替えることができます。
編集
私はそれは私がそれを閉じるために投票して達成または私の問題にしたいものを、この質問から明らかではないと思います。私は、私が探しているものをより良く述べるための考え方を思いついたので、私は新しい質問を出したいと思います。
あなたはどのようなエラーメッセージを得るのですか?質問を洗練されたものにすることができますか? –
(コメントへの誤った答えの変更): 't_STATES'から' t_BECOME'までのキーワードに対応するパターン変数は、 't_NAME'が最初に試されるので決して成功しません。しかし、Plyは 't_NAME'でマッチしていない入力のどの位置でもマッチさせようとしますが、これは非常に非効率的です。変数を削除すると、コードを読みやすく、メンテナンス性が向上し、やや速くなります。 – rici
@riciあなたが言っていることを得るが、正しく動作する。ファイル中の 'STATES'は' t_STATES'と認識されます。 't_NAME'の定義は、処理された文字列がキーワードでないかどうかを調べることです。または私は間違っていますか? –