JavaCC Problem - Generierter Code findet nicht alle Parse-Fehler
-
19-09-2019 - |
Frage
begann einfach mit JavaCC. Aber ich habe ein seltsames Verhalten mit ihm. Ich mag Eingabe von Zeichen (Buchstaben und Zahlen) int Form überprüfen Weichen mit Zeichen verkettet (+, -, /) und Weichen Klammern enthalten. Ich hoffe, das war verständlich:)
In der Haupt-Methode ist eine Zeichenfolge, die einen Fehler erzeugen sollen, weil es eine Öffnung, sondern zwei schließende Klammer, aber ich habe keine Parse Ausnahme erhalten -> Warum
Hat jemand eine Ahnung, warum ich nicht die Ausnahme bekommen Sie?
Ich kämpfe mit dem linken Rekursion und Wahl Konflikten mit meinem ersten Versuch, aber geschaffen, über sie zu bekommen. Vielleicht gibt eingeführt ich das Problem?!
Oh - und vielleicht ist meine Lösung nicht sehr gut - diese Tatsache ignorieren ... oder besser, einen Rat geben ;-)
Datei: CodeParser.jj
options {
STATIC=false;
}
PARSER_BEGIN(CodeParser)
package com.testing;
import java.io.StringReader;
import java.io.Reader;
public class CodeParser {
public CodeParser(String s)
{
this((Reader)(new StringReader(s)));
}
public static void main(String args[])
{
try
{
/** String has one open, but two closing parenthesis --> should produce parse error */
String s = "A+BC+-(2XXL+A/-B))";
CodeParser parser = new CodeParser(s);
parser.expression();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
PARSER_END(CodeParser)
TOKEN:
{
<code : ("-")?(["A"-"Z", "0"-"9"])+ >
| <op : ("+"|"/") >
| <not : ("-") >
| <lparenthesis : ("(") >
| <rparenthesis : (")") >
}
void expression() :
{
}
{
negated_expression() | parenthesis_expression() | LOOKAHEAD(2) operator_expression() | <code>
}
void negated_expression() :
{
}
{
<not>parenthesis_expression()
}
void parenthesis_expression() :
{
}
{
<lparenthesis>expression()<rparenthesis>
}
void operator_expression() :
{
}
{
<code><op>expression()
}
Bearbeiten - 11/16/2009
Nun gab ich ANTLR versuchen.
änderte ich einige Begriffe besser zu meinem Problem Domain entsprechen. Ich kam mit dem folgenden Code (mit den Antworten auf dieser Seite) auf, die die Arbeit jetzt zu tun scheint:
grammar Code;
CODE : ('A'..'Z'|'0'..'9')+;
OP : '+'|'/';
start : terms EOF;
terms : term (OP term)*;
term : '-'? CODE
| '-'? '(' terms ')';
Und übrigens ... ANTLRWorks ist ein großes Werkzeug für die Fehlersuche / Visualisierung! Hat mir sehr geholfen.
Weitere Informationen
Above-Code übereinstimmt Sachen wie:
(-Z19+-Z07+((FV+((M005+(M272/M276))/((M278/M273/M642)+-M005)))/(FW+(M005+(M273/M278/M642)))))+(-Z19+-Z07+((FV+((M005+(M272/M276))/((M278/M273/M642/M651)+-M005)))/(FW+(M0))))
Lösung
Was kgregory sagt, ist die richtige Antwort. Sie können das sehen, wenn Sie die Grammatik mit der DEBUG_PARSER Option bauen und sie dann ausführen:
$ javacc -debug_parser -output_directory=com/testing/ CodeParser.jj && javac com/testing/*.java && java -cp . com.testing.CodeParser Java Compiler Compiler Version 5.0 (Parser Generator) (type "javacc" with no arguments for help) Reading from file CodeParser.jj . . . File "TokenMgrError.java" is being rebuilt. File "ParseException.java" is being rebuilt. File "Token.java" is being rebuilt. File "SimpleCharStream.java" is being rebuilt. Parser generated successfully. Call: expression Call: operator_expression Consumed token: <<code>: "A" at line 1 column 1> Consumed token: <<op>: "+" at line 1 column 2> Call: expression Call: operator_expression Consumed token: <<code>: "BC" at line 1 column 3> Consumed token: <<op>: "+" at line 1 column 5> Call: expression Call: negated_expression Consumed token: <"-" at line 1 column 6> Call: parenthesis_expression Consumed token: <"(" at line 1 column 7> Call: expression Call: operator_expression Consumed token: <<code>: "2XXL" at line 1 column 8> Consumed token: <<op>: "+" at line 1 column 12> Call: expression Call: operator_expression Consumed token: <<code>: "A" at line 1 column 13> Consumed token: <<op>: "/" at line 1 column 14> Call: expression Consumed token: <<code>: "-B" at line 1 column 15> Return: expression Return: operator_expression Return: expression Return: operator_expression Return: expression Consumed token: <")" at line 1 column 17> Return: parenthesis_expression Return: negated_expression Return: expression Return: operator_expression Return: expression Return: operator_expression Return: expression
Sehen Sie das? Der letzte Token verbraucht ist die zweite zum letzten Zeichen - die zweitletzte rechten Klammer.
Wenn Sie die Ausnahme wollen, wieder, wie kgregory sagte, eine neue Top-Level-Produktion „Datei“ oder „Daten“ oder etwas und lassen Sie ihn mit einem Token genannt hinzufügen könnte. Auf diese Weise alle baumelnden Pars wie dies würde einen Fehler verursachen. Hier ist eine Grammatik, die das tut:
options { STATIC=false; } PARSER_BEGIN(CodeParser) package com.testing; import java.io.StringReader; import java.io.Reader; public class CodeParser { public CodeParser(String s) { this((Reader)(new StringReader(s))); } public static void main(String args[]) { try { /** String has one open, but two closing parenthesis --> should produce parse error */ String s = "A+BC+-(2XXL+A/-B))"; CodeParser parser = new CodeParser(s); parser.file(); } catch(Exception e) { e.printStackTrace(); } } } PARSER_END(CodeParser) TOKEN: { <code : ("-")?(["A"-"Z", "0"-"9"])+ > | <op : ("+"|"/") > | <not : ("-") > | <lparenthesis : ("(") > | <rparenthesis : (")") > } void file() : {} { expression() <EOF> } void expression() : { } { negated_expression() | parenthesis_expression() | LOOKAHEAD(2) operator_expression() | <code> } void negated_expression() : { } { <not>parenthesis_expression() } void parenthesis_expression() : { } { <lparenthesis>expression()<rparenthesis> } void operator_expression() : { } { <code><op>expression() }
Und ein Probelauf:
$ javacc -debug_parser -output_directory=com/testing/ CodeParser.jj && javac com/testing/*.java && java -cp . com.testing.CodeParser Java Compiler Compiler Version 5.0 (Parser Generator) (type "javacc" with no arguments for help) Reading from file CodeParser.jj . . . File "TokenMgrError.java" is being rebuilt. File "ParseException.java" is being rebuilt. File "Token.java" is being rebuilt. File "SimpleCharStream.java" is being rebuilt. Parser generated successfully. Call: file Call: expression Call: operator_expression Consumed token: <<code>: "A" at line 1 column 1> Consumed token: <<op>: "+" at line 1 column 2> Call: expression Call: operator_expression Consumed token: <<code>: "BC" at line 1 column 3> Consumed token: <<op>: "+" at line 1 column 5> Call: expression Call: negated_expression Consumed token: <"-" at line 1 column 6> Call: parenthesis_expression Consumed token: <"(" at line 1 column 7> Call: expression Call: operator_expression Consumed token: <<code>: "2XXL" at line 1 column 8> Consumed token: <<op>: "+" at line 1 column 12> Call: expression Call: operator_expression Consumed token: <<code>: "A" at line 1 column 13> Consumed token: <<op>: "/" at line 1 column 14> Call: expression Consumed token: <<code>: "-B" at line 1 column 15> Return: expression Return: operator_expression Return: expression Return: operator_expression Return: expression Consumed token: <")" at line 1 column 17> Return: parenthesis_expression Return: negated_expression Return: expression Return: operator_expression Return: expression Return: operator_expression Return: expression Return: file com.testing.ParseException: Encountered " ")" ") "" at line 1, column 18. Was expecting: <EOF> at com.testing.CodeParser.generateParseException(CodeParser.java:354) at com.testing.CodeParser.jj_consume_token(CodeParser.java:238) at com.testing.CodeParser.file(CodeParser.java:34) at com.testing.CodeParser.main(CodeParser.java:22)
Voila! Eine Ausnahme.
Andere Tipps
Von dem Java CC FAQ
4.7 Ich habe Eine vorwärts Spezifikation und die Warnung ging weg; heißt das ich das Problem behoben?
Nein. JavaCC nicht Wahl Konflikt Warnungen melden, wenn Sie Eine vorwärts Spezifikation verwenden. Die Fehlen einer Warnung bedeutet nicht, dass Sie das Problem richtig gelöst haben, ist es nur bedeutet, dass Sie hinzugefügt Eine vorwärts Spezifikation .
ich anfangen würde, indem sie versuchen, loszuwerden, den Konflikt zu kommen, ohne zunächst einen Look-Ahead verwendet wird.
Das Problem ist, dass Sie nicht den Fehler, wenn der Parser verwenden, richtig? Nicht, dass der Parser-Generator wird behauptet, dass die Grammatik falsch ist (was die Diskussion in der anderen Antwort zu sein scheint).
Wenn das der Fall ist, dann vermute ich, dass Sie das Problem sind zu sehen, weil der Parser richtig paßt die Ausdruck Produktion, dann nachfolgende Eingabe ignoriert. Ich habe nicht JavaCC für längere Zeit nicht benutzt, aber iirc hat es nicht einen Fehler für nicht erreicht End-of-Stream werfen.
Die meisten Grammatiken haben eine explizite Top-Level-Produktion die gesamte Datei entsprechen, so etwas wie folgt aussehen (ich bin sicher, dass die Syntax falsch ist, wie gesagt, es war eine lange Zeit):
input : ( expression ) *
Oder gibt es wahrscheinlich ein EOF-Token, das Sie verwenden können, wenn Sie nur einen einzigen Ausdruck bearbeiten wollen.