javaCC "java.lang.ArrayIndexOutOfBoundsException: -1" 异常
javaCC "java.lang.ArrayIndexOutOfBoundsException: -1" exception
我有一个 IT 研究项目,它是为只为该项目制作的简单语言制作一个编译器(它是一个简化的 java)。为了解析语法,我在 javacc 中为第一个版本制作了一个 jjtree 文件(我们必须在这个项目中使用 SCRUM 方法),所以它还没有完整的语法。起初它似乎工作得很好,并且可以正确阅读我输入的内容。但是,当我们与项目中的另一个人(我们是一个五人小组)一起为 jjtree 生成的每个访问者编写编译规则时,我们发现了多项选择规则的一些问题。我们看到要解决这个问题,我们必须在语法上使用标签,这就是我们开始遇到问题的地方。
我在一些规则上添加了标签(尤其是有多项选择的规则),现在,当我们测试解析器时,它在变量声明中给了我们一个异常。例如:
class C{
int i=1;
main {
i++;
}
}
当我输入“;”时,在int i=1之后给出了异常。
class C{
int i[1];
main {
i++;
}
}
在int i[1]
中第二个“]”后给出异常
当我输入“;”时,在int i=1之后给出了异常。
class C{
int i;
int x;
main {
i++;
}
}
进入main时报异常
例外情况:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(ArrayList.java:418)
at java.util.ArrayList.remove(ArrayList.java:495)
at JJTGrammaireJavaCCASA2State.closeNodeScope(JJTGrammaireJavaCCASA2State.java:86)
at GrammaireJavaCCASA2.classe(GrammaireJavaCCASA2.java:50)
at GrammaireJavaCCASA2.main(GrammaireJavaCCASA2.java:9)
有人可以帮助我吗?我是 javaCC 的新手,我坚持了两周。我找不到哪里有问题,而且我还有一些标签问题,所以它可能来自这里。
这是老师给我们的基本语法(它是法语的,但我认为即使不懂法语也很容易理解)和我们为 javaCC 重写的语法(我们使用黄色的版本 1) :
最后是 javaCC 中的代码(我删除了 space 的评论,因为它们是法语的,但我可以重新添加):
options {
VISITOR = true;
MULTI=true;
}
PARSER_BEGIN(GrammaireJavaCCASA2)
import java.io.*;
public class GrammaireJavaCCASA2 {
public static void main(String args[]) throws ParseException {
GrammaireJavaCCASA2 parser = new GrammaireJavaCCASA2(System.in);
SimpleNode root = parser.classe();
root.dump("");
}
}
PARSER_END(GrammaireJavaCCASA2)
SKIP : {
" "
| "\t"
| "\n"
| "\r"
}
TOKEN :{
<VIRGULE : ",">
| <PVIRGULE : ";">
| <PAROUV : "(">
| <PARFER : ")">
| <ACCOLOUV: "{">
| <ACCOLFER: "}">
| <CROOUV: "[">
| <CROFER : "]">
| <PLUS : "+">
| <MOINS : "-">
| <MULT : "*">
| <DIV : "/">
| <AFFECTATION : "=">
| <PLUSEGAL : "+=">
| <INCREMENT : "++">
| <EGALE : "==">
| <SUPERIEUR : ">">
| <DIFFERENT : "!">
| <ET : "&&">
| <OU : "||" >
| <CLASSE : "class">
| <FINAL : "final">
| <MAIN : "main">
| <VOID : "void">
| <RETURN : "return">
| <IF : "if">
| <ELSE : "else">
| <WHILE : "while">
| <TRUE : "true">
| <FALSE : "false">
| <NOMBRE : (["0"-"9"])+>
| <INT : "int">
| <BOOLEAN : "boolean">
| <IDENT : ["a"-"z","A"-"Z"] ( ["a"-"z","A"-"Z","0"-"9"] )*>
}
SimpleNode classe() #CLASSE(3): {}{
<CLASSE> ident() <ACCOLOUV> decls() methmain() <ACCOLFER>{return jjtThis;}
}
void ident() #IDENT: {Token t;}{
t=<IDENT> {jjtThis.value = t.image;}
}
void decls() #DECLS(2): {}{
decl() <PVIRGULE> decls()
|{} #VNIL
}
void decl() #DECL(1) : {}{
vars()
}
void vars() #VARS(2): {}{
var() <PVIRGULE> vars()
|{} #VNIL
}
void var() #void : {}{
typemeth() ident() (<CROOUV> exp() <CROFER> #TABLEAU(3)|vexp() #VAR(3))
}
/*void Var2() : {}{
Vexp()
}*/
void vexp() #AFFECTATIONINIT(1) : {}{
<AFFECTATION> exp()
|{} #OMEGA
}
void methmain() #MAIN(2): {}{
<MAIN> <ACCOLOUV> vars() instrs() <ACCOLFER>
}
void instrs() #INSTRS(2): {}{
instr() <PVIRGULE> instrs()
|{} #INIL
}
void instr() #void : {}{
ident1() (<AFFECTATION> exp() #AFFECTATION(2)
|<PLUSEGAL> exp() #SOMME(2)
|<INCREMENT> #INCREMENT(1))
}
/*void Instr2() : {}{
<AFFECTATION> Exp()
|<PLUSEGAL> Exp()
|<INCREMENT>
}*/
void exp() #EXP1GO(1) : {}{
exp1()
}
void exp1() #EXP1(1): {}{
exp2()
}
void exp2() #void : {}{
<MOINS> terme() [exp2prime()] #NEGATIF(2)
|terme() [exp2prime()] #TERMEEXP(2)
}
void exp2prime() #void : {}{
<PLUS> terme() [exp2prime()] #PLUS(2)
|<MOINS> terme() [exp2prime()] #MOINS(2)
}
void terme() #TERME(2): {}{
fact() [termeprime()]
}
void termeprime() #void : {}{
<MULT> fact() [termeprime()] #PRODUIT(2)
|<DIV> fact() [termeprime()] #DIVISION(2)
}
void fact() #void : {}{
ident1() #IDENT1GO(1)
|<TRUE> #VRAI
|<FALSE> #FAUX
|<NOMBRE> #NOMBRE
}
void ident1() #IDENT1(1) : {}{
ident()
}
void typemeth() #TYPE(1): {}{
type()
}
void type() #void : {}{
<INT> #ENTIER
|<BOOLEAN> #BOOLEEN
}
在此先感谢您的帮助,抱歉我的英语不好。如果您需要更多信息,请随时询问。
我觉得下面的作品不对
void decls() #DECLS(2): {}{
decl() <PVIRGULE> decls()
|{} #VNIL
}
考虑没有声明的情况。然后,首先,一个 VNIL
将被压入堆栈,其次,两个节点将从堆栈中弹出,一个 DECL
节点将被压入堆栈。因此,它不会按照您的意愿向堆栈中添加一个节点,而是用 DECL
节点替换顶部节点。
这样写比较好:
void decls() #void : {}{
(decl() <PVIRGULE> decls()) #DECLS
|
{} #VNIL
}
或
void decls() #void : {}{ someDecls() | nothing() }
void someDecls() #DECLS : {} { decl() <PVIRGULE> decls() }
void nothing() #VNIL : {} { }
类似的评论适用于您语法中的许多作品。
您也可以像这样避免使用 VNIL
void decls() #DECLS : {} { decl() ( <PVIRGULE> decl() )* }
祝你好运。
我有一个 IT 研究项目,它是为只为该项目制作的简单语言制作一个编译器(它是一个简化的 java)。为了解析语法,我在 javacc 中为第一个版本制作了一个 jjtree 文件(我们必须在这个项目中使用 SCRUM 方法),所以它还没有完整的语法。起初它似乎工作得很好,并且可以正确阅读我输入的内容。但是,当我们与项目中的另一个人(我们是一个五人小组)一起为 jjtree 生成的每个访问者编写编译规则时,我们发现了多项选择规则的一些问题。我们看到要解决这个问题,我们必须在语法上使用标签,这就是我们开始遇到问题的地方。
我在一些规则上添加了标签(尤其是有多项选择的规则),现在,当我们测试解析器时,它在变量声明中给了我们一个异常。例如:
class C{
int i=1;
main {
i++;
}
}
当我输入“;”时,在int i=1之后给出了异常。
class C{
int i[1];
main {
i++;
}
}
在int i[1]
中第二个“]”后给出异常当我输入“;”时,在int i=1之后给出了异常。
class C{
int i;
int x;
main {
i++;
}
}
进入main时报异常
例外情况:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(ArrayList.java:418)
at java.util.ArrayList.remove(ArrayList.java:495)
at JJTGrammaireJavaCCASA2State.closeNodeScope(JJTGrammaireJavaCCASA2State.java:86)
at GrammaireJavaCCASA2.classe(GrammaireJavaCCASA2.java:50)
at GrammaireJavaCCASA2.main(GrammaireJavaCCASA2.java:9)
有人可以帮助我吗?我是 javaCC 的新手,我坚持了两周。我找不到哪里有问题,而且我还有一些标签问题,所以它可能来自这里。
这是老师给我们的基本语法(它是法语的,但我认为即使不懂法语也很容易理解)和我们为 javaCC 重写的语法(我们使用黄色的版本 1) :
最后是 javaCC 中的代码(我删除了 space 的评论,因为它们是法语的,但我可以重新添加):
options {
VISITOR = true;
MULTI=true;
}
PARSER_BEGIN(GrammaireJavaCCASA2)
import java.io.*;
public class GrammaireJavaCCASA2 {
public static void main(String args[]) throws ParseException {
GrammaireJavaCCASA2 parser = new GrammaireJavaCCASA2(System.in);
SimpleNode root = parser.classe();
root.dump("");
}
}
PARSER_END(GrammaireJavaCCASA2)
SKIP : {
" "
| "\t"
| "\n"
| "\r"
}
TOKEN :{
<VIRGULE : ",">
| <PVIRGULE : ";">
| <PAROUV : "(">
| <PARFER : ")">
| <ACCOLOUV: "{">
| <ACCOLFER: "}">
| <CROOUV: "[">
| <CROFER : "]">
| <PLUS : "+">
| <MOINS : "-">
| <MULT : "*">
| <DIV : "/">
| <AFFECTATION : "=">
| <PLUSEGAL : "+=">
| <INCREMENT : "++">
| <EGALE : "==">
| <SUPERIEUR : ">">
| <DIFFERENT : "!">
| <ET : "&&">
| <OU : "||" >
| <CLASSE : "class">
| <FINAL : "final">
| <MAIN : "main">
| <VOID : "void">
| <RETURN : "return">
| <IF : "if">
| <ELSE : "else">
| <WHILE : "while">
| <TRUE : "true">
| <FALSE : "false">
| <NOMBRE : (["0"-"9"])+>
| <INT : "int">
| <BOOLEAN : "boolean">
| <IDENT : ["a"-"z","A"-"Z"] ( ["a"-"z","A"-"Z","0"-"9"] )*>
}
SimpleNode classe() #CLASSE(3): {}{
<CLASSE> ident() <ACCOLOUV> decls() methmain() <ACCOLFER>{return jjtThis;}
}
void ident() #IDENT: {Token t;}{
t=<IDENT> {jjtThis.value = t.image;}
}
void decls() #DECLS(2): {}{
decl() <PVIRGULE> decls()
|{} #VNIL
}
void decl() #DECL(1) : {}{
vars()
}
void vars() #VARS(2): {}{
var() <PVIRGULE> vars()
|{} #VNIL
}
void var() #void : {}{
typemeth() ident() (<CROOUV> exp() <CROFER> #TABLEAU(3)|vexp() #VAR(3))
}
/*void Var2() : {}{
Vexp()
}*/
void vexp() #AFFECTATIONINIT(1) : {}{
<AFFECTATION> exp()
|{} #OMEGA
}
void methmain() #MAIN(2): {}{
<MAIN> <ACCOLOUV> vars() instrs() <ACCOLFER>
}
void instrs() #INSTRS(2): {}{
instr() <PVIRGULE> instrs()
|{} #INIL
}
void instr() #void : {}{
ident1() (<AFFECTATION> exp() #AFFECTATION(2)
|<PLUSEGAL> exp() #SOMME(2)
|<INCREMENT> #INCREMENT(1))
}
/*void Instr2() : {}{
<AFFECTATION> Exp()
|<PLUSEGAL> Exp()
|<INCREMENT>
}*/
void exp() #EXP1GO(1) : {}{
exp1()
}
void exp1() #EXP1(1): {}{
exp2()
}
void exp2() #void : {}{
<MOINS> terme() [exp2prime()] #NEGATIF(2)
|terme() [exp2prime()] #TERMEEXP(2)
}
void exp2prime() #void : {}{
<PLUS> terme() [exp2prime()] #PLUS(2)
|<MOINS> terme() [exp2prime()] #MOINS(2)
}
void terme() #TERME(2): {}{
fact() [termeprime()]
}
void termeprime() #void : {}{
<MULT> fact() [termeprime()] #PRODUIT(2)
|<DIV> fact() [termeprime()] #DIVISION(2)
}
void fact() #void : {}{
ident1() #IDENT1GO(1)
|<TRUE> #VRAI
|<FALSE> #FAUX
|<NOMBRE> #NOMBRE
}
void ident1() #IDENT1(1) : {}{
ident()
}
void typemeth() #TYPE(1): {}{
type()
}
void type() #void : {}{
<INT> #ENTIER
|<BOOLEAN> #BOOLEEN
}
在此先感谢您的帮助,抱歉我的英语不好。如果您需要更多信息,请随时询问。
我觉得下面的作品不对
void decls() #DECLS(2): {}{
decl() <PVIRGULE> decls()
|{} #VNIL
}
考虑没有声明的情况。然后,首先,一个 VNIL
将被压入堆栈,其次,两个节点将从堆栈中弹出,一个 DECL
节点将被压入堆栈。因此,它不会按照您的意愿向堆栈中添加一个节点,而是用 DECL
节点替换顶部节点。
这样写比较好:
void decls() #void : {}{
(decl() <PVIRGULE> decls()) #DECLS
|
{} #VNIL
}
或
void decls() #void : {}{ someDecls() | nothing() }
void someDecls() #DECLS : {} { decl() <PVIRGULE> decls() }
void nothing() #VNIL : {} { }
类似的评论适用于您语法中的许多作品。
您也可以像这样避免使用 VNIL
void decls() #DECLS : {} { decl() ( <PVIRGULE> decl() )* }
祝你好运。