Javacc解析器生成器无法识别我的语言(输入)

时间:2017-11-29 02:51:16

标签: parsing pascal javacc parser-generator

我正在与Javacc合作为Pascal子集构建解析器。

这是我的代码:

PARSER_BEGIN(Pascal)
import java.io.*;
public class Pascal {

  public static void main(String args[]) throws ParseException,IOException {

    Pascal parser = new Pascal(new FileInputStream(args[0]));
    parser.Programa();
  }

}

PARSER_END(Pascal)

SKIP :
{
  " "
| "\t"
| "\n"
| "\r"
}

TOKEN :
{
  <PROGRAM: "program">
| <INTEIRO: "integer">
| <REAL: "real">
| <VAR: "var">
| <OF: "of">
| <FUNCTION: "function">
| <PROCEDURE: "procedure">
| <LBRACE:"(">
| <RBRACE: ")">
| <SEMI: ";">
| <PTS: ":">
| <BEGIN: "begin">
| <END: "end">
| <ATRIB: ":=">
| <ARRAY: "array">
| <LBRACKETS: "[">
| <RBRACKETS: "]">
| <IF: "if">
| <THEN: "then">
| <ELSE: "else">
| <NOT: "not">
| <PLUS: "+">
| <MINUS: "-">
| <WHILE: "while">
| <DO: "do">
}

TOKEN :
{
 <OPERADOR_MULTIPLICATIVO: ("*"|"/"|"div"|"mod"|"and")>
|
 <OPERADOR_ADITIVO: ("+"| "-" | "or")>
|
 <OPERADOR_RELACIONAL: ("=" | "<>" | "<" | "<=" | ">=" | ">")>
|
 <ID: ["a"-"z","A"-"Z"] ( ["a"-"z","A"-"Z","0"-"9"])*>
|
 <DIGT: ["0"-"9"] (["0"-"9"])*>

}



void Programa () :
{}
{ <PROGRAM> <ID> <LBRACE> Lista_de_identificadores() <RBRACE> <SEMI> 
  Declaracoes()
  Declara_subprogram() 
  Enunciado_composto()
  <EOF> 
}

// lista_de_identificadores

void Lista_de_identificadores():
{}
{
  <ID> Lista2()
}

void Lista2():
{}
{
 ("," <ID> Lista2())?
}

//declarações

void Declaracoes():
{}
{
    (<VAR> Lista_de_identificadores() <PTS> Tipo() <SEMI>)*
}

// tipo

void Tipo():
{}
{
    (Tipo_padrao() | <ARRAY> <LBRACKETS> <DIGT> <RBRACKETS> <OF> Tipo_padrao())
}

//tipo_padrao

void Tipo_padrao():
{}
{
    (<INTEIRO> | <REAL>)
}

//declarações_de_subprogramas

void Declara_subprogram():
{}
{
    (Subprogram() <SEMI>)*
}

//declaração_de_subprograma

void Subprogram():
{}
{
    Cabecalho_subprogram()
    Declaracoes()
    Enunciado_composto()
}

//cabeçalho_de_subprograma

void Cabecalho_subprogram():
{}
{
    (<FUNCTION> <ID> Argumentos() <PTS> Tipo_padrao() <SEMI>) | (<PROCEDURE> <ID> Argumentos())
}

//argumentos

void Argumentos():
{}
{
    (<LBRACE> Lista_parametros() <RBRACE>)?
}

//lista_de_parâmetros

void Lista_parametros():
{}
{
    Lista_de_identificadores() <PTS> Tipo() Lista_parametros2()
}

void Lista_parametros2():
{}
{
    (<SEMI> Lista_de_identificadores() <PTS> Tipo() Lista_parametros2())?
}

//enunciado_composto

void Enunciado_composto():
{}
{
    <BEGIN> Enunciados_opcionais() <END>    
}

//enunciados_opcionais

void Enunciados_opcionais():
{}
{
    (Lista_enunciados())?
}

//lista_de_enunciados

void Lista_enunciados():
{}
{
    Enunciado() (<SEMI> Enunciado())*
}

void Enunciado():
{}
{
    LOOKAHEAD(5)(Variavel() <ATRIB> Expressao()) | (Chamada_procedimento()) | (Enunciado_composto()) | (<IF> Expressao() <THEN> Enunciado() <ELSE> Enunciado()) | (<WHILE> Expressao() <DO> Enunciado())
}

void Variavel():
{}
{
    LOOKAHEAD(2)(<ID>) | (<ID> <LBRACKETS> Expressao() <RBRACKETS>)
}

void Chamada_procedimento():
{}
{
    LOOKAHEAD(2)(<ID>) | (<ID> <LBRACE> Lista_expressoes() <RBRACE>)
}

void Lista_expressoes():
{}
{
    Expressao() Lista_expressoes2() 
}

void Lista_expressoes2():
{}
{
    ("," Expressao() Lista_expressoes2())?
}

void Expressao():
{}
{
    LOOKAHEAD(2)Expressao_simples() | Expressao_simples() <OPERADOR_RELACIONAL> Expressao_simples()
}

void Expressao_simples():
{}
{
    LOOKAHEAD(3)(Termo() Expressao_simples2()) | (Sinal() Termo() Expressao_simples2())
}

void Expressao_simples2():
{}
{
    (<OPERADOR_ADITIVO> Termo() Expressao_simples2())?
}

void Termo():
{}
{
    Fator() Termo2()
}

void Termo2():
{}
{
    (<OPERADOR_MULTIPLICATIVO> Fator() Termo2())?
}

void Fator():
{}
{
    LOOKAHEAD(2)(<ID>) | (<ID> <LBRACE> Lista_expressoes() <RBRACE>) | (<DIGT>) | (<LBRACE> Expressao() <RBRACE>) | (<NOT> Fator())
}

void Sinal():
{}
{
    (<PLUS> | <MINUS>)
}

这是输入程序:

program exemplo (input, output, test);
var x, y: integer;
function mdc (a, b: integer): integer;
begin
    if b = 0 then mdc := a
    else mdc := mdc (b, a mod b)
end;

begin
    read(x, y);
    write(mdc(x,y));
end;

Javacc返回:

Exception in thread "main" ParseException: Encountered " <OPERADOR_RELACIONAL> "= "" at line 5, column 14.
Was expecting one of:
    "then" ...
    <OPERADOR_MULTIPLICATIVO> ...
    <OPERADOR_ADITIVO> ...
    <OPERADOR_MULTIPLICATIVO> ...
    <OPERADOR_ADITIVO> ...
    <OPERADOR_ADITIVO> ...
    <OPERADOR_MULTIPLICATIVO> ...
    <OPERADOR_ADITIVO> ...

        at Pascal.generateParseException(Pascal.java:984)
        at Pascal.jj_consume_token(Pascal.java:865)
        at Pascal.Enunciado(Pascal.java:270)
        at Pascal.Lista_enunciados(Pascal.java:235)
        at Pascal.Enunciados_opcionais(Pascal.java:223)
        at Pascal.Enunciado_composto(Pascal.java:211)
        at Pascal.Subprogram(Pascal.java:137)
        at Pascal.Declara_subprogram(Pascal.java:127)
        at Pascal.Programa(Pascal.java:20)
        at Pascal.main(Pascal.java:9)

问题是,我无法理解为什么Javacc期待这些论点并调用&#34; =&#34;他所处的位置错了。关于这个具体情境的工作部分是这一部分(几乎是完整的代码):

void Enunciado():
{}
{
    LOOKAHEAD(5)(Variavel() <ATRIB> Expressao()) | (Chamada_procedimento()) | (Enunciado_composto()) | (<IF> Expressao() <THEN> Enunciado() <ELSE> Enunciado()) | (<WHILE> Expressao() <DO> Enunciado())
}

void Variavel():
{}
{
    LOOKAHEAD(2)(<ID>) | (<ID> <LBRACKETS> Expressao() <RBRACKETS>)
}

void Chamada_procedimento():
{}
{
    LOOKAHEAD(2)(<ID>) | (<ID> <LBRACE> Lista_expressoes() <RBRACE>)
}

void Lista_expressoes():
{}
{
    Expressao() Lista_expressoes2() 
}

void Lista_expressoes2():
{}
{
    ("," Expressao() Lista_expressoes2())?
}

void Expressao():
{}
{
    LOOKAHEAD(2)Expressao_simples() | Expressao_simples() <OPERADOR_RELACIONAL> Expressao_simples()
}

void Expressao_simples():
{}
{
    LOOKAHEAD(3)(Termo() Expressao_simples2()) | (Sinal() Termo() Expressao_simples2())
}

void Expressao_simples2():
{}
{
    (<OPERADOR_ADITIVO> Termo() Expressao_simples2())?
}

void Termo():
{}
{
    Fator() Termo2()
}

void Termo2():
{}
{
    (<OPERADOR_MULTIPLICATIVO> Fator() Termo2())?
}

void Fator():
{}
{
    LOOKAHEAD(2)(<ID>) | (<ID> <LBRACE> Lista_expressoes() <RBRACE>) | (<DIGT>) | (<LBRACE> Expressao() <RBRACE>) | (<NOT> Fator())
}

有人可以弄清楚错误在哪里?我已经尝试了很多东西,但现在看起来对我来说很好(事实上并非如此)。 感谢。

编辑:具有相同名称但最终编号为2的函数用于消除左递归。

2 个答案:

答案 0 :(得分:2)

问题是你使用LOOKAHEAD的方式是行不通的。例如,你有

  LOOKAHEAD(2)Expressao_simples()
| Expressao_simples() <OPERADOR_RELACIONAL> Expressao_simples()

这就是说,如果下两个输入令牌与Expressao_simples一致,则采用第一种选择,否则采取第二种选择。显然,在第二种替代方案可能成功的任何情况下,接下来的两个代币也将与第一种替代方案一致,因此将选择第一种代币。

相反,您可以将选择推迟到以后

Expressao_simples()
( 
    <OPERADOR_RELACIONAL> Expressao_simples()
)?

将此代码与Pascal报告(修订版)中的图表进行比较。 enter image description here

答案 1 :(得分:1)

我没有可用于测试的特定解析器/生成器, 但似乎奇怪的是解析器似乎'= '有关 作为单一的标记。我先调查一下。 如果这没有揭示问题,那么下一步要调查 是您对Expressao_simples的定义。

我担心调查此类问题的最简单方法有点 痛苦 - 暂时将语法剥离到最简单的情况,请参阅 如果解析器接受了它,如果是,则扩展语法并重新测试 直到你发现问题为止。

换句话说,首先将PROGRAM定义为

PROGRAM : "a" "=" "b"

如果解析器接受了,请尝试

PROGRAM : IDENTIFIER "=" IDENTIFIER

然后

PROGRAM : IDENTIFIER RELATIONALOPERATOR IDENTIFIER

然后

PROGRAM : SIMPLEEXPRESSION RELATIONALOPERATOR SIMPLEEXPRESSION

等。最终,您应该找到导致问题的构造。

我会说“祝你好运!”,但你真的不需要它,只需要很多耐心 和简单的测试用例。