2017-10-30 3 views
0

アルゴリズムの動作の説明で入力ファイルを処理しようとしています。私は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_sectionsecond_sectionに切り替えることができます。

編集

私はそれは私がそれを閉じるために投票して達成または私の問題にしたいものを、この質問から明らかではないと思います。私は、私が探しているものをより良く述べるための考え方を思いついたので、私は新しい質問を出したいと思います。

+0

あなたはどのようなエラーメッセージを得るのですか?質問を洗練されたものにすることができますか? –

+0

(コメントへの誤った答えの変更): 't_STATES'から' t_BECOME'までのキーワードに対応するパターン変数は、 't_NAME'が最初に試されるので決して成功しません。しかし、Plyは 't_NAME'でマッチしていない入力のどの位置でもマッチさせようとしますが、これは非常に非効率的です。変数を削除すると、コードを読みやすく、メンテナンス性が向上し、やや速くなります。 – rici

+0

@riciあなたが言っていることを得るが、正しく動作する。ファイル中の 'STATES'は' t_STATES'と認識されます。 't_NAME'の定義は、処理された文字列がキーワードでないかどうかを調べることです。または私は間違っていますか? –

答えて

1

Oups!あなたの文法は、ファイルを1行ずつ解析します。これは少なくとも珍しく、行の順序を制御することはできません。 IMHO、ファイル全体を解析する必要があります。トリックは、パーサに一度に一つのラインとのレクサーを供給し、ラインで構成する各セクションを宣言しますtokenfunc機能を渡すことです:

class Parser(object): 
    def p_algorithm(self, p): 
     ''' algorithm : first_section second_section''' 

    def p_first_section(self, p): 
     ''' first_section : first_section_line 
          | first_section_line first_section''' 

    def p_first_section_line(self, p): 
     ''' first_section_line : STATES EQUALS states_list SEMICOLON 
          | REGISTERS EQUALS register_list SEMICOLON 
          | INIT EQUALS init_list SEMICOLON 
          | TERM EQUALS term_list SEMICOLON''' 

    ... 
    # same for second section... 

    @prepare_file 
    def parsing(self, file): 
     def get_token(): 
      'a tokenizer that automatically feeds the lexer with the next line' 
      while True: 
       tok = self.lexer._lexer.token() 
       if tok is not None: return tok 
       try: 
        line = next(file) 
        self.lexer._lexer.input(line) 
       except StopIteration: 
        return None 

     self._parser.parse("", lexer=self.lexer._lexer, tokenfunc = get_token) 
+0

正確に。行ごとに解析するのは問題だが、解決方法はわからない。私は今作業していますが、セミコロンを追加してセミコロンを追加して、セミコロンが現れない限り、行を読み込み、連結し始めました。例えば、2行を1つに連結し、解析しました。 –

+0

@ M.Pukどこにでも改行を受け入れるかどうかは、あなた次第です。レクサーが改行とタブを無視するので、私は線が折れる可能性があると仮定し、インデントも無視されました。 –

+0

私はあなたのアイデアを試みます。ユーザーがどこにでもセミコロンを入力しないようにする。はい、すべての空白文字を無視する必要があります。私の問題は、ユーザーが正しくファイルを書き込めるように、たとえば 'state_behavior:NAME begin commands end'のようなルールを定義したかったということでした。 –

関連する問題