Хорошо, я понял.Но, к сожалению, я не могу опубликовать весь свой код здесь как есть.В любом случае, я постараюсь наметить решение и, если что-то неясно, задавайте вопросы.
JFlex использует свой собственный класс Symbol
.Посмотрите здесь: JFlex.jar / java_cup.runtime / Symbol.class
Вы увидите добавленную пару конструкторов:
public Symbol(int id, Symbol left, Symbol right, Object o){
this(id,left.left,right.right,o);
}
public Symbol(int id, Symbol left, Symbol right){
this(id,left.left,right.right);
}
Ключ здесь Object o
, который является значениемof Symbol.
Определите свой собственный класс для представления узла дерева AST, а другой - для представления токена лексера.Конечно, вы можете использовать один и тот же класс, но я обнаружил, что более понятно использовать разные классы для различия между ними.И JFlex, и CUP будут генерировать Java-код, и ваши токены и узлы легко перепутать.
Затем в вашем parser.flex, в разделах лексических правил, вы захотите сделать что-то подобноедля каждого токена:
{float_lit} { return symbol(sym.NUMBER, createToken(yytext(), yycolumn)); }
Сделайте это для всех своих токенов.Ваш createToken может выглядеть примерно так:
%{
private LexerToken createToken(String val, int start) {
LexerToken tk = new LexerToken(val, start);
addToken(tk);
return tk;
}
}%
Теперь давайте перейдем к parser.cup.Объявите все ваши терминалы типа LexerToken
и все ваши нетерминалы типа Node
.Вы хотите прочитать руководство CUP, но для быстрого освежения терминалом будет все, что распознается лексером (например, числа, переменные, операторы), а нетерминалом будут части вашей грамматики (например, выражение, коэффициент, термин ...).
Наконец, все это объединяется в определении грамматики.Рассмотрим следующий пример:
factor ::= factor:f TIMES:times term:t
{: RESULT = new Node(times.val, f, t, times.start); :}
|
factor:f DIVIDE:div term:t
{: RESULT = new Node(div.val, f, t, div.start); :}
|
term:t
{: RESULT = t; :}
;
Синтаксис factor:f
означает, что вы называете значение коэффициента равным f
, и вы можете обратиться к нему в следующем разделе {: ... :}
.Помните, что наши терминалы имеют значения типа LexerToken
, а наши нетерминалы имеют значения Node
s.
Ваш термин в выражении может иметь следующее определение:
term ::= LPAREN expr:e RPAREN
{: RESULT = new Node(e.val, e.start); :}
|
NUMBER:n
{: RESULT = new Node(n.val, n.start); :}
;
Когда вы успешно сгенерируете код синтаксического анализатора, вы увидите в вашем файле parser.java ту часть, где установлены отношения родитель-потомок между узлами:
case 16: // term ::= UFUN LPAREN expr RPAREN
{
Node RESULT =null;
int ufleft = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-3)).left;
int ufright = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-3)).right;
LexerToken uf = (LexerToken)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-3)).value;
int eleft = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-1)).left;
int eright = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-1)).right;
Node e = (Node)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-1)).value;
RESULT = new Node(uf.val, e, null, uf.start);
CUP$parser$result = parser.getSymbolFactory().newSymbol("term",0, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-3)), ((java_cup.runtime.Symbol)CUP$parser$stack.peek()), RESULT);
}
return CUP$parser$result;
Я сожалею, что не могу опубликовать полный пример кода,но, надеюсь, это сэкономит кому-то несколько часов проб и ошибок.Не иметь полного кода также хорошо, потому что он не сделает все эти домашние задания CS бесполезными.
В качестве доказательства жизни приведу симпатичную распечатку моего образца AST.
Входное выражение:
T21 + 1A / log(max(F1004036, min(a1, a2))) * MIN(1B, 434) -LOG(xyz) - -3.5+10 -.1 + .3 * (1)
Результирующий AST:
|--[+]
|--[-]
| |--[+]
| | |--[-]
| | | |--[-]
| | | | |--[+]
| | | | | |--[T21]
| | | | | |--[*]
| | | | | |--[/]
| | | | | | |--[1A]
| | | | | | |--[LOG]
| | | | | | |--[MAX]
| | | | | | |--[F1004036]
| | | | | | |--[MIN]
| | | | | | |--[A1]
| | | | | | |--[A2]
| | | | | |--[MIN]
| | | | | |--[1B]
| | | | | |--[434]
| | | | |--[LOG]
| | | | |--[XYZ]
| | | |--[-]
| | | |--[3.5]
| | |--[10]
| |--[.1]
|--[*]
|--[.3]
|--[1]