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 <% e
SyntaxTree* 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
してはいけない。