JFlex で CUP を使用して、式の構文を検証しています。基本的な機能は動作しています。式が有効かどうかを判断できます。
次のステップは、「1 を足す」などの単純な算術演算を実装することです。たとえば、式が「1 + a」の場合、結果は「2 + a」になるはずです。これを行うには、構文解析ツリーにアクセスする必要があります。単に数値用語を識別するだけでは不十分なためです。「(1 + a) * b」に 1 を加算した結果は、「(1 + a) * b + 1」になるはずです。 、「(2 + a) * b」ではありません。
解析ツリーを生成する CUP の例はありますか? そこから取れると思います。
追加のボーナスとして、JFlex を使用して式のすべてのトークンのリストを取得する方法はありますか? 典型的なユースケースのように思えますが、それを行う方法がわかりません。
編集:スタックオーバーフローに関する有望な手がかりが見つかりました: パーサーから抽象ツリーの問題を作成する
CUP と AST の議論:
http://pages.cs.wisc.edu/~fischer/cs536.s08/lectures/Lecture16.4up.pdf
具体的には、この段落:
パーサーによって返された Symbol は、文法の開始記号に関連付けられており、ソース プログラム全体の AST が含まれています。
これは役に立ちません。Symbol クラスにその子へのナビゲーション ポインタがない場合、Symbolインスタンスを指定してツリーをトラバースする方法は? つまり、ツリー ノードのように見えたり、動作したりしません。
package java_cup.runtime;
/**
* Defines the Symbol class, which is used to represent all terminals
* and nonterminals while parsing. The lexer should pass CUP Symbols
* and CUP returns a Symbol.
*
* @version last updated: 7/3/96
* @author Frank Flannery
*/
/* ****************************************************************
Class Symbol
what the parser expects to receive from the lexer.
the token is identified as follows:
sym: the symbol type
parse_state: the parse state.
value: is the lexical value of type Object
left : is the left position in the original input file
right: is the right position in the original input file
******************************************************************/
public class Symbol {
/*******************************
Constructor for l,r values
*******************************/
public Symbol(int id, int l, int r, Object o) {
this(id);
left = l;
right = r;
value = o;
}
/*******************************
Constructor for no l,r values
********************************/
public Symbol(int id, Object o) {
this(id, -1, -1, o);
}
/*****************************
Constructor for no value
***************************/
public Symbol(int id, int l, int r) {
this(id, l, r, null);
}
/***********************************
Constructor for no value or l,r
***********************************/
public Symbol(int sym_num) {
this(sym_num, -1);
left = -1;
right = -1;
value = null;
}
/***********************************
Constructor to give a start state
***********************************/
Symbol(int sym_num, int state)
{
sym = sym_num;
parse_state = state;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The symbol number of the terminal or non terminal being represented */
public int sym;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The parse state to be recorded on the parse stack with this symbol.
* This field is for the convenience of the parser and shouldn't be
* modified except by the parser.
*/
public int parse_state;
/** This allows us to catch some errors caused by scanners recycling
* symbols. For the use of the parser only. [CSA, 23-Jul-1999] */
boolean used_by_parser = false;
/*******************************
The data passed to parser
*******************************/
public int left, right;
public Object value;
/*****************************
Printing this token out. (Override for pretty-print).
****************************/
public String toString() { return "#"+sym; }
}