Parser クラスの子クラスであり、メンバ関数
SyntaxTree* parse(void) を持つ。Number であれば、クラス名は P_Number
というように、頭に P_ がついたものとなる。p_ がついたものとなる。P_Number クラスなら p_Number
という名前のインスタンスとなる。Number の解析をしたいのであれば、SyntaxTree* st = p_Number->parse();Number <- [0-9]+P_Numberクラスが定義され、メンバ関数void P_Number::action(SyntaxTree*, Application*)void P_Number::actionAtParse(SyntaxTree*)actionAtParse() は、パースが成功した時点で呼ばれる。$ctype を実現するために使用している。#include のような動作をさせるために使用できるだろう。action() は、パースが正常終了したらその結果を渡して呼び出す。SyntaxTree::action()
から呼ばれる場合がほとんどで、その方が便利。SyntaxTree::action(Application* ap) の中身はparser->action(this, ap)
という処理になっているので、SyntaxTreeを生成したParserのaction()が呼ばれる。SyntaxTree*
st = p_Number->parse();if (st->isValidTree()) {
st->action(&app); // 結果が app に入る} |
A <- B $3 C
というルールがあり、これを元にパースし、B が成功して $3 を通過した後 C が失敗すると、
エラーとなり、A の errorMessage関数が呼ばれる。
引数として、3 と、パースに失敗した位置(この場合は C の位置)が渡される。
A <% eSyntaxTree* P_A::uParse(void)プログラマは uParse()
関数を実装しなければならない。actionAtParse()関数は宣言されない。SyntaxTree オブジェクトに格納される。SyntaxTreeは、Parserオブジェクトへのポイン
タSyntaxTreeの配列オブジェク
トへのポインタSubstr構造体で入力開始位置と
終了位置)Number <- [0-9]+[0-9] となる。123ab をNumberでパースすると、消
費した入力は 123 となる。SyntaxTreeは3つとなり、最初の子は 1 を消費し、Number <- %[0-9]+% の機能により子が生成したSyntaxTreeは
全部捨てられ、0個になる。SyntaxTreeは3つの子"+" が infixl、 "**"
が infixr
の場合、入力とそのパース結果のSyntaxTreeをおおまかに示すと以下の
ようになる。1+2+3 → (("1","+","2"),"+","3")
1**2**3 → ("1","**",("2","**","3"))
これを元に演算を実行する場合、各子の action()
を呼んで、その結果を使って自分の演算をするような action() をプログラムすれば良い。| 真となる判定関数 | 意味 | 定義済み値 | |
|---|---|---|---|
| 正常値 | isValidTree() |
成功したパース結果を保持する。 | |
| 結果を削除 | == _NO_SYNTAX_TREE |
成功だが、値を捨てた状態。 | _NO_SYNTAX_TREE |
| パース失敗 | isFail(), isFailNotError() |
パースに失敗した状態。 | _PARSE_FAILED |
| エラーカット | isErrorCut() |
ErrorCutを示す。この後にパース失敗するとそれはエラーとなるように内部的に処理される。ErrorCut番号 を保持する。 | |
| エラー | isFail(), isError() |
ErrorCut機能によりパース失敗がエラーに変換されたもの。ErrorCut番号を保持する。内部的に ErrorMessage()を呼び出し、その後は致命的エラー状態になる。 | |
| 致命的エラー | isFail(), isError(), isFatalError() |
パースもエラー処理もこれ以上行わないで終了させる状態。 | _FATAL_PARSER_ERROR |
Applicationクラスはユーザーが任意に定義する。action()で SyntaxTree
を処理した結果を Application オブジェクトに格納する。Number で解析したものを整数にしたければ、struct Application {
int x;
};
としてvoid P_Number::action(SyntaxTree* st, Application* ap)
{
(整数に変換する処理)
ap->x = (結果の整数)
}
とすれば良いだろう。'token')を使う場合は、ユーザーが NotTokenPred
ルールを定義しなければならない。
入力を消費しないようにする事。 ! か &
を使えば入力を消費しない。NotTokenPred <- !([a-z]/[A-Z]/[0-9]/"_")Applicationクラスを定義するInputBufferを生成するParser::initialize()を呼ぶ_PARSE_FAILED ならパース失敗_NO_SYNTAX_TREE なら成功だが結果の情報は無し_FATAL_PARSER_ERROR
ならこれ以上パース出来ない致命的エラー状態isValidTree()がtrueを
返せば、有効なSyntaxTreeオブジェクトApplicationオブジェクトを用意し、SyntaxTreeオ
ブジェクトの action() を呼ぶと、対応するパーサの action()
が呼ばれる。Application オブジェクトに格納される。SyntaxTree や Application
オブジェクトは delete する。Parser::finalize()
を呼ぶ。これで、生成された Parser は全て delete
される。逆にユーザーは自分で new したものであっても Parser
を自分で delete してはいけない。