2017-07-21 14 views
0

私は自分のミニ言語のパーサーを構築しようとしています(明らかに)、変数の設定が適切に機能しているようです。しかし、Yaccが関数定義を見つけるとすぐに、構文エラーといくつかのEOFエラー(私はYaccに残りのルールが設定されていないときからそうであることを知っています)は何も起こりません。うまくいかない?Python PLY Yacc "構文エラー"

はここで構文私はパースてるの例です:

$name = "John Doe" 
$age = 72 
$waterInOceans = 95.4 

!testFunction { 

} 

!testFunction { }セクションでは、(感嘆符のオフに基づいて)関数を定義しています。それがデバッグに役立つかどうかはわかりません。

# The Lexer 

import ply.lex as lex 

tokens = ["MINUS", "SEPARATOR", "MODIFIER", "FUNCTION_NAME", "UNDEF_BLOCK", "VARIABLE_NAME", "EQUALS", "STRING", "FLOAT", "INNER_CONTENT", "ARGUMENTS", "INTEGER", "PLUS"] 

def t_ARGUMENTS(t): # Finds arguments in calls and function definitions 
    r'\(.*\)' 
    t.value = t.value[1:-1] # strip parenthesis 
    t.value = t.value.split(" && ") 
    return t 

def t_STRING(t): # finds strings 
    r'"\w.+"' 
    t.value = t.value[1:-1] # strips the quotation marks of the string 
    return t 

def t_FLOAT(t): # finds floats 
    r'\d+.\d+' 
    t.value = float(t.value) 
    return t 

def t_INTEGER(t): 
    r'\d+' 
    t.value = int(t.value) 
    return t 

def t_VARIABLE_NAME(t): 
    r'\$\w*\b' 
    t.value = t.value[1:] 
    return t 

def t_INNER_CONTENT(t): 
    r'\{\n.*\n\}|\{.*\}' 
    t.value = t.value[1:-1] 
    return t 

def t_FUNCTION_NAME(t): 
    r'!\w+' 
    t.value = t.value[1:] 
    return t 

t_ignore = r"\n|\t|\r" 
t_EQUALS = r"\=" 
t_PLUS = r"\+" 
t_MINUS = r"-" 
t_MODIFIER = r"\." 
t_SEPARATOR = r"\," 

t_UNDEF_BLOCK = r"\w+" # Any block of text that is left over and isn't assigned by the end (used by functions) 

def t_error(t): 
    t.lexer.skip(1) 

lex.lex() 

#opened = open("example.zeq", "r") 
#content = opened.read() 
#opened.close() 

#lex.input(content) 

そしてYaccの半分:あなたはプライ(またはYACCを頼むとき

# The Yacc parser 

import ply.yacc as yacc 
import compiler # Get the compiler (tokenizer; compiler.py) which generates tokens 
import sys 
from os import system 


############## 
### IGNORE ### 
tokens = compiler.tokens 
#system("clear") 
print("Executing "+sys.argv[1]+" |\n"+("-"*(len(sys.argv[1])+12))) 
### IGNORE ### 
############## 


VARIABLES = {} 
FUNCTIONS = {} 

def p_assign(p): # Set new variable 
    '''assignment : VARIABLE_NAME EQUALS compound 
        | VARIABLE_NAME EQUALS STRING 
        | VARIABLE_NAME EQUALS INTEGER 
        | VARIABLE_NAME EQUALS FLOAT''' 

    #print("Setting '{}' to '{}'...".format(str(p[1]), str(p[3]))) 
    VARIABLES[p[1]] = p[3] 

def p_number(p): # Combines floats and integers into a blanket non-terminal for simplicity sakes 
    '''number : FLOAT 
       | INTEGER''' 
    p[0] = p[1] 

def p_compound(p): # Complete the value *before* the variable is assigned! 
    '''compound : number PLUS number 
       | number MINUS number''' 

    type1 = type(p[1]) 
    type2 = type(p[3]) 
    operator = p[2] 
    if operator == "+": 
     p[0] = p[1] + p[3] 
    elif operator == "-": 
     p[0] = p[1] - p[3] 

def p_undefined(p): 
    '''undefined : UNDEF_BLOCK''' 
    print("Undefined block") 

def p_function(p): 
    '''function : FUNCTION_NAME INNER_CONTENT''' 

    print("Creating a function") 

    name = p[1] 
    content = p[2] 

    FUNCTIONS[name] = content 

def p_empty(p): 
    '''empty : ''' 

#~ def p_error(p): 
    #~ if p: 
     #~ print("Syntax error: "+p.type) 
    #~ else: 
     #~ pass 

parser = yacc.yacc() 

opened = open(sys.argv[1], "r") 
content = opened.read() 
opened.close() 

for line in content.splitlines(): 
    parser.parse(line) 

print(VARIABLES) 
print(FUNCTIONS) 

それはシンプルであるために、私は待ってはそのことについては、...

答えて

0

を細部を見落とし)を使用して入力を解析すると、最上位の非終端記号(または「開始記号」)の1つのインスタンスを認識しようとします。これは通常、入力全体の文法的な記述なので、入力の一部だけを解析するのに便利なユースケースがありますが、しばしばprogramのような名前を持ちます。

Ply(およびyacc)は、最初の文法生成が開始シンボル用であると仮定します。あなたの場合、最初の生産はassignmentなので、それが解析しようとするものです。 assignmentは、関数定義やその他の文の型を派生できないため、構文エラーが発生します。

トップレベルシンボルが何であるかを明示的にPlyに伝えたい場合は、そうすることができます。 the manual section on starting symbolsを参照してください。

+0

少し前にこれを閉じるのを忘れました。私はこの問題を完全に解決した新しい言語のための新しいパーサーの作業を開始しました。あなたに感謝してくれてありがとう! –