Только начал с JavaCC. Но у меня странное поведение с ним. Я хочу проверить ввод в виде токенов (букв и цифр), которые объединены знаками (+, -, /) и могут содержать круглые скобки. Надеюсь понятно было :)
В основном методе есть строка, которая должна выдавать ошибку, потому что у нее одна открывающая и две закрывающие скобки, но я не получаю исключение синтаксического анализа --> Почему?
Кто-нибудь знает, почему я не получаю исключение?
Я боролся с левой рекурсией и конфликтами выбора при первой попытке, но мне удалось их преодолеть. Может, там я привнес проблему?!
О, и, возможно, мое решение не очень хорошее - игнорируйте этот факт... или лучше дайте совет ;-)
Файл: 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()
}
Редактировать - 16.11.2009
Теперь я попробовал ANTLR.
Я изменил некоторые термины, чтобы лучше соответствовать моей предметной области. Я придумал следующий код (используя ответы на этом сайте), который, похоже, теперь работает:
grammar Code;
CODE : ('A'..'Z'|'0'..'9')+;
OP : '+'|'/';
start : terms EOF;
terms : term (OP term)*;
term : '-'? CODE
| '-'? '(' terms ')';
И кстати... ANTLRWORKS - отличный инструмент для отладки/визуализации! Мне очень помог.
Дополнительная информация
Вышеприведенный код соответствует таким вещам, как:
(-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))))
Ответ 1 · рейтинг 3 · tomcopeland
То, что говорит кггрегори, является правильным ответом. Вы можете увидеть это, если создадите грамматику с параметром DEBUG_PARSER, а затем запустите ее:
$ 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
Видеть, что? Последний потребляемый токен - это предпоследний символ - предпоследняя правая скобка.
Если вам нужно исключение, опять же, как сказал kgregory, вы можете добавить новое производство верхнего уровня под названием "файл" или "данные" или что-то еще и закончить его токеном. Таким образом, любые висячие скобки, подобные этому, вызовут ошибку. Вот грамматика, которая делает это:
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()
}
И пример запуска:
$ 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)
Вуаля! Исключение.
Ответ 2 · рейтинг 1 · rsp
Из часто задаваемых вопросов по Java CC :
4.7 Я добавил спецификацию ПРОГНОЗ, и предупреждение исчезло; значит ли это, что я исправил проблему?
Нет. JavaCC не будет сообщать о предупреждениях о конфликте выбора, если вы используете спецификацию LOOKAHEAD. Отсутствие предупреждения не означает, что вы решили проблему правильно, это просто означает, что вы добавили спецификацию LOOKAHEAD.
Я бы начал с попытки избавиться от конфликта без использования просмотра вперед.
Ответ 3 · рейтинг 1 · kdgregory
Проблема в том, что вы не получаете ошибку при использовании парсера, верно? Не то чтобы генератор синтаксического анализатора утверждает, что грамматика неверна (что, кажется, обсуждается в другом ответе).
Если это так, то я подозреваю, что вы видите проблему, потому что синтаксический анализатор правильно сопоставляет выражение, а затем игнорирует последующий ввод. Я давно не использовал JavaCC, но iirc не выдавал ошибку из-за того, что не достиг конца потока.
Большинство грамматик имеют явное производство верхнего уровня для соответствия всему файлу, выглядящее примерно так (я уверен, что синтаксис неправильный, как я уже сказал, это было давно):
input : ( expression ) *
Или, возможно, есть токен EOF, который вы можете использовать, если хотите обработать только одно выражение.