JavaCC Problema - código gerado não encontrar todos os erros de análise
-
19-09-2019 - |
Pergunta
Apenas começou com JavaCC. Mas eu tenho um comportamento estranho com ele. Eu quero verificar a entrada int a forma de fichas (letras e números) wich são concatenados com sinais (+, -, /) e wich pode conter parênteses. Espero que era compreensível:)
No método principal é uma string, que deve produzir um erro, porque ele tem uma abertura, mas dois parêntese de fechamento, mas eu não obter uma exceção de análise -> Por
Alguém tem uma pista por isso que eu não entendo a exceção?
Eu estava lutando com recursão e escolha conflitos esquerda com minha tentativa inicial, mas conseguiu superá-los. Talvez lá eu introduziu o problema?!
Oh - e talvez a minha solução não é muito bom - ignorar esse fato ... ou melhor, dar alguns conselhos ;-)
arquivo: 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()
}
Editar - 11/16/2009
Agora que eu dei ANTLR uma tentativa.
Eu mudei alguns termos para corresponder melhor o meu domínio do problema. Eu vim com o seguinte código (usando as respostas neste site), que parece estar a fazer o trabalho agora:
grammar Code;
CODE : ('A'..'Z'|'0'..'9')+;
OP : '+'|'/';
start : terms EOF;
terms : term (OP term)*;
term : '-'? CODE
| '-'? '(' terms ')';
E pelo jeito ... ANTLRWORKS é uma grande ferramenta para depuração / visualizar! Ajudou-me muito.
adicionais informações
Acima de código corresponde coisas como:
(-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))))
Solução
O que kgregory diz é a resposta certa. Você pode ver isso se você construir a gramática com a opção DEBUG_PARSER e depois executá-lo:
$ 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
Veja isso? O último token consumido é o segundo a última personagem - o segundo a última parêntese direito.
Se você quiser a exceção, novamente, como kgregory disse, você pode adicionar uma nova produção de nível superior chamado "arquivo" ou "dados" ou algo assim e terminá-la com um token. Dessa forma, qualquer parens pendurados como este iria causar um erro. Aqui está uma gramática que faz isso:
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() }
E uma corrida de exemplo:
$ 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! Uma exceção.
Outras dicas
A partir da Java CC FAQ :
4,7 Eu adicionei uma especificação LookAhead eo aviso foi embora; Isso significa que corrigiu o problema?
No. JavaCC não irá relatar avisos de conflito escolha se você utilizar uma especificação LookAhead. O ausência de um aviso não significa que você resolveu o problema corretamente, ele apenas significa que você adicionou um LookAhead especificação .
Gostaria de começar por tentar livrar-se do conflito sem usar uma visão antecipada em primeiro lugar.
O problema é que você não obter o erro ao usar o analisador, correto? Não que o gerador de analisador está reivindicando que a gramática está incorreta (que parece ser a discussão na outra resposta).
Se for esse o caso, então eu suspeito que você está vendo o problema porque o analisador corresponde corretamente o expressão produção, em seguida, ignora a entrada posterior. Eu não usei JavaCC por um longo tempo, mas IIRC não lançar um erro por não alcançar fim-de-stream.
A maioria das gramáticas têm uma produção de nível superior explícita para combinar o arquivo inteiro, procurando algo assim (eu tenho certeza que a sintaxe é errado, como eu disse, tem sido um longo tempo):
input : ( expression ) *
Ou, provavelmente há um EOF símbolo que você pode usar, se você deseja processar apenas uma única expressão.