2017-07-21 79 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的一半:

# 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

當你問簾布層(或yacc的,對於這個問題)來解析輸入時,它會嘗試識別頂級非終端(或「起始符號」)的單個實例。這通常是對整個輸入的語法描述,所以它通常會有一個名稱,如program,儘管有些用例只是解析一部分輸入。

Ply(和yacc)假定第一個文法生產是用於起始符號的。在你的情況下,第一個產品是assignment,所以這是它將嘗試解析(而不是別的)。 assignment不能派生函數定義或任何其他語句類型,所以這些導致語法錯誤。

如果您想明確告訴Ply什麼是頂級符號,您可以這樣做。見the manual section on starting symbols

+0

我剛纔忘了關閉它。我已經開始爲一種新語言開發新的解析器,以完全解決這個問題。儘管謝謝你願意回答! –