Modifica: Ho fatto una prima versione, che Eike mi ha aiutato ad avanzare un po 'su di esso. Ora sono bloccato a un problema più specifico, che descriverò qui sotto. Si può avere uno sguardo alla domanda originale nella historyMigliorare i messaggi di errore con pyparsing
sto usando pyparsing di analizzare un piccolo linguaggio utilizzato per richiedere dati specifici da un database. Dispone di numerose parole chiave, operatori e tipi di dati, oltre alla logica booleana.
Sto cercando di migliorare il messaggio di errore inviato all'utente quando fa un errore di sintassi, poiché quello corrente non è molto utile. Ho progettato un piccolo esempio, simile a quello che sto facendo con la lingua di cui sopra, ma molto più piccolo:
#!/usr/bin/env python
from pyparsing import *
def validate_number(s, loc, tokens):
if int(tokens[0]) != 0:
raise ParseFatalException(s, loc, "number musth be 0")
def fail(s, loc, tokens):
raise ParseFatalException(s, loc, "Unknown token %s" % tokens[0])
def fail_value(s, loc, expr, err):
raise ParseFatalException(s, loc, "Wrong value")
number = Word(nums).setParseAction(validate_number).setFailAction(fail_value)
operator = Literal("=")
error = Word(alphas).setParseAction(fail)
rules = MatchFirst([
Literal('x') + operator + number,
])
rules = operatorPrecedence(rules | error , [
(Literal("and"), 2, opAssoc.RIGHT),
])
def try_parse(expression):
try:
rules.parseString(expression, parseAll=True)
except Exception as e:
msg = str(e)
print("%s: %s" % (msg, expression))
print(" " * (len("%s: " % msg) + (e.loc)) + "^^^")
Quindi, in pratica, le uniche cose che possiamo fare con questo linguaggio, sta scrivendo una serie di x = 0
, uniti con and
e parentesi.
Ora, ci sono casi in cui vengono utilizzati and
e parentesi, in cui la segnalazione degli errori non è molto buona. Considerate i seguenti esempi:
>>> try_parse("x = a and x = 0") # This one is actually good!
Wrong value (at char 4), (line:1, col:5): x = a and x = 0
^^^
>>> try_parse("x = 0 and x = a")
Expected end of text (at char 6), (line:1, col:1): x = 0 and x = a
^^^
>>> try_parse("x = 0 and (x = 0 and (x = 0 and (x = a)))")
Expected end of text (at char 6), (line:1, col:1): x = 0 and (x = 0 and (x = 0 and (x = a)))
^^^
>>> try_parse("x = 0 and (x = 0 and (x = 0 and (x = 0)))")
Expected end of text (at char 6), (line:1, col:1): x = 0 and (x = 0 and (x = 0 and (xxxxxxxx = 0)))
^^^
In realtà, sembra che se il parser non è in grado di analizzare (e parse qui è importante) qualcosa dopo un and
, non produce più buoni messaggi di errore: (
E intendo parse, in quanto se è in grado di analizzare 5, ma la "validazione" fallisce nell'azione parse, produce ancora un buon messaggio di errore. ma, se non in grado di analizzare un numero valido (come a
) o una parola chiave valida (come xxxxxx
), arresta il prodotto cingendo i giusti messaggi di errore.
Qualche idea?
avere un'azione convalida parse per i nomi delle variabili troppo. Oppure prendi un nome con tutte le variabili come "Word (alphas)" e applica un'azione di analisi, che genera sempre un'eccezione. – Eike
In alternativa è possibile eseguire la convalida di un livello. Avere un parser 'Word (alphas) -" == "- Word (nums)' e mettere su di esso un'azione di analisi più complessa, che cerca nomi di variabili legali e garantisce la correttezza dei numeri. – Eike
Al momento, che sarebbe una soluzione di ultima resort :) –