汎用パーサー・汎用ジェネレータ・汎用グラフデータ操作です。

第0.43版 2016年10月23日
第0.38版 2008年 2月10日

compiled_syntax al_symbol_manip("compile_syntax", syntax, null, null, opt);

syntaxで定義された文法を内部表現に変換してlist型を返します。
syntaxの型は読み込みのfileです。変換エラーの場合、エラー情報を含むstringが返ります。
optが opt-/"debug"/->1の形式のときは文法のコンパイル途中情報をアウトプットウィンドウに出力します。

parse_tree al_symbol_manip("parse", input, compiled_syntax, id, opt);

内部表現になった文法compiled_syntaxを用いてinputをパースし、
パースツリーをlist型で返します。inputの型は読み込みのfileです。
パースエラーの場合、エラー情報を含むstringが返ります。
idには、文法中に現れる「単位構文のid」を入れます。

opt に opt-/"debug"/->(level10, level20, level30) を入れるとlevelに合わせてパース途中のデバッグ情報がダンプされます。
levelxxの形式は以下です。
  形式                                意味
  null                                デバッグ出力しません。
 start_lno-/unit_name/=>()            行番号が start_lno 以降デバッグ出力します。
                                      unit_name が一個もない場合は全文法ユニットの情報がが出力されます。
                                      unit_name がある場合は、その unit_name の文法ユニットの情報だけが出力されます。
 (start_lno, end_lno)-/unit_name/=>() 行番号が start_lno から end_lno の間だけデバッグ出力します。
                                      unit_name が一個もない場合は全文法ユニットの情報がが出力されます。
                                      unit_name がある場合は、その unit_name の文法ユニットの情報だけが出力されます。
出力されるデバッグ情報は以下です。
  level10 成功した単位構文IDとそのソース上の行番号。
  level20 成功した単位構文IDとそのソース上の先頭の行番号と行番号。
  level30 成功した単位構文IDとそのソース上の行番号。
          試行を開始する単位構文IDとそのソース上の行番号。
          文法定義ファイル中の固定文字列のtokenの成否とそのソース上の行番号。
          文法定義ファイル中の字句解析の成否とそのソース上での行番号。
          試行した単位構文のIDとその成否とソース上の行番号。
デフォルトの parse では、parseツリーの大きさが大きくならないよう、省略可能なノードを省略するようになっています。
opt に opt-/"full"/->1 を入れるとこれらのノードを省略しないままの parse ツリーが返されます。

list al_symbol_manip("generate", output, compiled_syntax, parse_tree, opt);

内部表現になった文法compiled_syntaxとパースツリーparse_treeから
parseで同じパースツリーが生成されるテキストを生成してoutputに書き込みます。
outputの型は書き込みのfileです。
テキスト生成エラー場合、エラー情報を含むstringが返ります。エラーのない場合は nullが返ります。

デフォルトでは token の間にスペースを1文字入れますが、optに非nullを入れるとスペースを入れません。

list al_symbol_manip("out_syntax_unit", output, compiled_syntax, null, opt);

内部表現になった文法compiled_syntaxからそれに含まれる単位構文の情報を
outputの書き込みのfile型ファイルに出力します。

opt に opt-/"skelton"/->1 を入れると変換ルールの手助けを行う為の
スケルトンも同時に出力されます。

【syntaxの文法】

● 構文 <構文定義> = "<" <構文名> ">" "=" <並列構文> ";" ; <並列構文> = <単位構文> { "|" <単位構文> }* ; // 2つにマッチするものは長いものを前に置く <括弧構文> = { "{" <並列構文> "}*" | "{" <並列構文> "}+" | "{" <並列構文> "}?" | "{" <並列構文> "}" } ; <単位構文> = <id> { <固定文字列> | <正規表現名> | <構文名> | <括弧構文> }+ ; ● 字句 <正規表現名> = regex <正規表現> <型> ; <型> = "integer" | "hex" | "char" | "real" | "string" | "quote_string" | "special" ; <正規表現> = { <単位表現> { "*" | "+" | "?" | "{" <整数> { "," { <整数> }? }? "}" }? }+ ; <単位表現> = "$" | "." | "(" <正規表現> { "|" <正規表現> }* ")" | "[^" <文字リスト> "]" | "[" <文字リスト> "]" | <文字> ; <文字リスト> = { <文字> "-" <文字> | <文字> }+ ; <文字> = <通常文字> | "\" <エスケープ文字> ; // \n 改行 // \M 全角文字 <通常文字> // 下記以外 "$" "." "*" "+" "?" "|" "{" "}" "(" ")" "[" "]" "\"

【compiled_syntaxとparse_teeのデータ構造】

● 構文 <構文定義> = "<" <構文名> ">" "=" <並列構文> ";" compiled_syntax (null)-/構文名/=>("{|}", ...) or (null)-/構文名/=>(id, ...) <固定文字列> compiled_syntax ("const", <固定文字列>) parse_tree - <正規表現> compiled_syntax ("regex", <正規表現>) parse_tree value <並列構文> = <単位構文> { "|" <単位構文> }* ";" // 2つにマッチするものは長いものを前に置く compiled_syntax ("{}", (id-1, ...), ... , (id-n, ...)) // n>1 (id-1, ...) // n=1 parse_tree (id-k, ...) <括弧構文> = { "{" <並列構文> "}*" | "{"<並列構文> "}+" | "{" <並列構文> "}?" | "{" <並列構文> "}" } ; compiled_syntax ("{}", (id-1, ...), ... , (id-n, ...)) ("{}*", ("{}", (id-1, ...), ... , (id-n, ...))) or ("{}*", (id, ...)) ("{}+", ("{}", (id-1, ...), ... , (id-n, ...))) or ("{}+", (id, ...)) ("{}?", ("{}", (id-1, ...), ... , (id-n, ...))) or ("{}?", (id, ...)) parse_tree (id-k1, ...) ("{}*", (id-k1, ...), ... , (id-km, ...)) // m>=0 ("{}+", (id-k1, ...), ... , (id-km, ...)) // m>=1 ("{}?", (id-k1, ...), ... , (id-km, ...)) // m=0 or m=1 <単位構文> = id { <固定文字列> | <正規表現名> | "<" <構文名> ">" | <括弧構文> }+ ; // idは1文法内でユニーク compiled_syntax (id {, ("const", <固定文字列>) | ("regex", <正規表現名>) | ("{}", ...) | ("{}*", ...) | ("{}+", ...) | ("{}?", ...) } + ) parse_tree (id, (...), (...), (...), ...) ● 字句 <正規表現> = { <単位表現> { "*" | "+" | "?" | "{" <整数> { "," { <整数> }? }? "}" }? }+ ; compiled_syntax ("regex", { ('*', unit) | ('+', unit) | ('?', unit) | ('{', n, m, unit) | unit }+ ) <単位表現> = "$" | "." | "(" <正規表現> { "|" <正規表現> }* ")" | "[^" <文字リスト> "]" | "[" <文字リスト> "]" | <文字> ; compiled_syntax ('$') | ('.') | ('(' ("regex", ...) { ("regex", ,,,) }* ) | ('!' ('|' { (b) | (b, e) }+ ) ) | ('[' ('|' { (b) | (b, e) }+ ) ) (0, c)

env al_symbol_manip("plisp_load", env, plisp_tree, null, null);

prologライクのリスト処理言語のパーズツリー plisp_tree をランタイム環境 env にロードし、
新しいランタイム環境 env を返します。引数の env が null だったら env が新しく作られます。
または、prologプログラムの parse_tree をロードしてランタイム環境 env にロードし、
新しいランタイム環境 env を返します。引数の env が null だったら env が新しく作られます。

result al_symbol_manip("plisp_call", env, function_name, arg_list, opt);

ランタイム環境 env で、関数名 function_name の関数を、
引数リスト arg_list で実行し、結果を返します。
エラーが発生した場合、エラー情報を含む AlException が throw されます。

optに opt-/"debug"/->debug を入れるとデバッグ情報がダンプされます。
debug に 10,20,30 のいずれかを入れた場合           levelに合わせてすべてのメソッドのデバッグ情報がダンプされます。
debug に (level, ()-/func_name/=>()) を入れた場合  名前func_name群のメソッドのデバッグ情報だけがダンプされます。

env al_symbol_manip("set_var", env, name, value, null);

altair側からprologライクのリスト処理言語側にデータを渡すための関数です。
plisp_call中で set_var(name, value) するのと同じです。
環境変数をランタイム環境 env にロードし、新しいランタイム環境 env を返します。

list al_symbol_manip("get_var", env, name, null, null);

prologライクのリスト処理言語側からaltair側にデータを渡すための関数です。
plisp_call中の get_var(name) するのと同じです。

list al_symbol_manip("prolog_exec", env, null, null, opt);

prologプログラムを実行します。Successの場合は null が、Failの場合は 1 が返ります。
prologライクのリスト処理言語で定義して環境envにロードしてある関数が、prologプログラム中で使えます。
Goalだけからなる問い合わせが複数ある場合、頭から順に実行し、
ひとつでもFailするとそこで戻り値 1 でリターンします。
Successしている間は実行を続け、すべての問い合わせがSuccessの場合だけ戻り値 null でリターンします。
途中でエラーが発生した場合、文字列が返ります。

このprologの実装方式は、以下の特許技術を用いています。
  特許出願公開番号 特開2000-148501
  公開日      平成12年5月30日(2000.5.30)

  出願番号 特願平10-328834
  出願日  平成10年11月4日(1998.11.4)
  出願人  日本電気株式会社
  発明者  稲本直太

  発明の名称 グラフ構造データを用いた論理型言語処理系の実現方式
        及びコンピュータ制御プログラムを格納した記憶媒体
optに opt-/"debug_pred"/->1 を入れると実行中の述語の名前の
デバッグ情報がダンプされます。出力部分例
optに opt-/"debug_dump"/->1 を入れると実行中の詳細なグラフ構造データの
デバッグ情報がダンプされます。出力部分例
ツリーグラフ変換の attr_grmr関数/inv_attr_grmr関数では、
optは、prolog_execの引数でなく、
attr_grmr関数/inv_attr_grmr関数の引数である事に注意してください。

以下は、plisp_call中で呼び出された、
ツリーグラフ変換の attr_grmr関数/inv_attr_grmr関数で出力される詳細ログです。
optは、prolog_execの引数でなく、
attr_grmr関数/inv_attr_grmr関数の引数である事に注意してください。

optに opt-/"debug_syn"/->1 を入れるとツリーグラフ変換中の文法変数の
デバッグ情報(単位文法に入った出た等)がダンプされます。出力部分例
optに opt-/"debug_syn2"/->1 を入れるとツリーグラフ変換中の文法変数の
デバッグ情報(制御情報等)がダンプされます。出力部分例
optに opt-/"debug_syn3"/->1 を入れるとツリーグラフ変換中の文法変数の
デバッグ情報(制御の末端情報等)がダンプされます。出力部分例

optに opt-/"debug_syntax_id"/->id を入れるとツリーグラフ変換中の指定した文法単位に着目した情報がダンプされます。
optに opt-/"debug_syntax_id2"/->id を入れるとツリーグラフ変換中の指定した文法単位に着目した情報がダンプされます。
optに opt-/"debug_syntax_id3"/->id を入れるとツリーグラフ変換中の指定した文法単位に着目した情報がダンプされます。
ダンプされる情報は、debug_pred, debug_synですが、
debug_syntax_id2は、debug_syn2, debug_syn3が加わり、
debug_syntax_id3は、debug_dumpが加わります。

Prologライクリスト処理言語中の「inv_attr_grmr(グラフ構造データからパースツリーに変換)」関数中で
エラーが発生した場合、この様なエラーログが出力されます。
ログの最後の方にある、
	 (in function 'inv_attr_grmr')
	
	StackTrace:
		ParGenConv::plisp_call
		ParGenConv::graph_to_tree
は、クラスライブラリ ParGenConv の 双方向グラフ構造データから 単方向 Lisp2進木データへの、
変換に失敗していることを表します。
ログの最初の所にある、
	graph_to_tree: runtime: lack of information for resolve.
		if1(10)
		loop1(8)
		if2(7)
		loop1(5)
	tree converion error: syntax_id = prim
		. . . 
	graph = ("mem_func")
	-/"arg_ls"/->("arg_ls")
	-/"name"/->("test")
	-/"obj"/->("ident")
		-/"name"/->("tp")
は、単位文法 prim 中で、変換が何らかの原因のため、
("mem_func") 以下のグラフ構造データで
グラフ構造データからLisp2進木データへの変換に失敗している事を表します。
ツリーグラフ変換ルール中の、
loop1 の5番め、if2 の7番目、loop1 の8番目、if1 の10番目で、
述語が一つも解決出来なかった事を示します。

デバッグオプションで、debug_pred, debug_syn をチェックして変換してみると
この様なデバッグ用のログが生成されます。

デバッグオプションで、debug_syntax_id2とdebug_syntax_id3 をチェックし、
単位文法にprimを入れて変換してみると
この様なデバッグ用のログが生成されます。

al_symbol_manip("clear_query", env, null, null, null);

ロードしたprologプログラムのうち、HeadとBodyからなるRuleはそのままにして
Goalだけからなる問い合わせをランタイム環境 env から削除します。

al_symbol_manip("clear_pred", env, null, null, null);

ロードしたprologプログラムのうち、GoalだけからなるQueryはそのままにして
HeadとBodyからなるRuleをランタイム環境 env から削除します。

al_symbol_manip("ls_pred", env, null, null, null);

ロードしたprologプログラムのうち、定義された述語の一覧を返します。

al_symbol_manip("plisp_max_call", count, null, null, null);

prologライクのリスト処理言語の関数コールの最大ネスト数を integer count で指定される値に設定します。
この値を超えると stack overflow の例外が発生します。デフォルトは、1024です。
count に null を入れると現在の設定値が返ります。

al_symbol_manip("prolog_max_call", count, null, null, null);

prologプログラムで述語を展開する最大ネスト数を integer count で指定される値に設定します。
この値を超えると stack overflow の例外が発生します。デフォルトは、1024です。
count に null を入れると現在の設定値が返ります。

【Prologライクリスト処理言語・拡張Prolog言語処理系の文法】

<program> = { <func_def> | <syntax_unit> | <prolog> }* EOF ; <func_def> = <ident> "(" { <ident> { "," <ident> }* }? ")" { <para> | <prog> }; <syntax_unit> = <ident> ":" <list_exp> "attr_grmr" { "{" <prolog> "}" | <stat> } ; /* -------- Prolog-Like List Processing -------- */ <para> = "{" { <sent> }* "}" ; <sent> = <cond> "->" { <cond> ";" | { <cond> "," }? <para> } ; <cond> = <or_exp> { "," <or_exp> }* ; /* -------- General Program -------- */ <prog> = "prog" <stat> ; <stat> = <block_stat> | <if_stat> | <return> | <while_stat> | <for_range_stat> | <for_list_stat> | <for_stat> | <inv_for_stat> | <switch_stat> | <exp_stat> ; <block_stat> = "{" { <stat> }* "}" ; <if_stat> = "if" "(" <exp> ")" <stat> { "else" <stat> }? ; <while_stat> = "while" "(" <exp> ")" <stat> ; <for_range_stat> = "for" <ident> "in" "[" <add_exp> ".." <add_exp> "]" <stat> ; <for_list_stat> = "for" <ident> "in" <exp> <stat> ; <for_stat> = "for" "(" <exp> ")" <stat> ; <inv_for_stat> = "inv_for" "(" <exp> ")" <stat> ; <switch_stat> = "switch" "(" <exp> ")" "{" { "case" <exp> ":" { <stat> }* }* "}" ; <return> = "return" { <exp> }? ";" ; <exp_stat> = <exp> ";" ; /* -------- General Expression -------- */ <exp> = <asgn_exp> ; <asgn_exp> = { <var> "=" }* <or_exp> ; <or_exp> = <and_exp> { "||" <and_exp> }* ; <and_exp> = <cmp_exp> { "&&" <cmp_exp> }* ; <cmp_exp> = <list_exp> { <cmp_op> <list_exp> }? ; <cmp_op> = "===" | "==" | "!=" | ">=" | ">" | "<=" | "<" ; <list_exp> = "(" <list_elem> { "," <list_elem> }* ")" | <add_exp> ; <list_elem> = <list_exp> "..." | "..." | <list_exp> ; <add_exp> = <mul_exp> { { "+" | "-" } <mul_exp> }* ; <mul_exp> = <prim_exp> { { "*" | "/" | "%" } <prim_exp> }* ; <prim_exp> = "null" | "true" | "break" | "continue" | "next" | <integer> | <string> | "-" <mul_exp> | "!" <mul_exp> | <func_exp> | "++" <var> | "--" <var> | <var> "++" | <var> "--" | <var> | <syn_var> | "(" <exp> ")" | "*" ; <func_exp> = <ident> "(" { <exp> { "," <exp> }* }? ")" ; <var> = <ident> | "$$" | <syn_loc> | <syn_gen> | <syn_tree> | <depth> | <count> ; <syn_var> = "$" { "[" <integer> "]" }+ ; <syn_loc> = regex \$[1-9] string ; <syn_gen> = regex \$gen string ; <syn_tree> = regex \$tree string ; <depth> = regex \$depth string ; <count> = regex \$count string ; <ident> = regex [A-Za-z_\M][A-Za-z0-9_\M]* string ; <integer> = regex \-?[0-9]+ integer ; <string> = regex "([^\\"]|\\.)*" quote_string ; // <comment_1> = comment /\*([^\*]|\*[^/])*\*/ ; // <comment_2> = comment //[^\n]*\n ; <comment_1> = comment_begin_end "/*" "*/" ; <comment_2> = comment_until_newline "//" ; /* -------- GraphData-Extended Prolog -------- */ <prolog> = { <goal> ":-" { <goals> }? "." | <goals> "." }+ ; <goals> = <goal> { "," <goal> }* ; <goal> = "not" "(" <goals> ")" | "brk_true_if" "(" <goals> ")" | "brk_false_if" "(" <goals> ")" | "cont_if" "(" <goals> ")" | "last" "(" <goals> ")" | "pm_rep" "(" <list_exp> { "," <list_exp> }* ")" { <before> <after> <common> <error> }+ <final> | <list_exp> <cmp_op> <grph_exp> | { "!" }? <ident> "(" <list_exp> { "," <list_exp> }* ")" ; /* -------- (Tree Graph Conversion) -------- */ <grph_exp> = <list_exp> { "[" "-/" <list_exp> "/->" "null" "]" | "[" "-/" <list_exp> "/->" <grph_exp> "]" }* ; /* -------- (Sub-Graph PatturnMatch and Replacement) -------- */ <before> = "before" ":=" "{" <sub_graph> { "," <sub_graph> }* "}" ; <after> = "after" ":=" "{" <sub_graph> { "," <sub_graph> }* "}" ; <common> = "common" ":=" "{" "where" { { <goals> }? "." }+ "}" ; <error> = "error" ":=" "{" "where" { { <goals> }? "." }+ "}" ; <final> = "final" ":=" "{" "where" { { <goals> }? "." }+ "}" ; <sub_graph> = "invariant" | { "?" }? <node> { "-/" <arc> "/->" | "-/" <arc> "/=>" | "<-/" <arc> "/-" | "<-/" <arc> "/=" } <node> { "?" }? | <node> ; <node> = <ident> { ":" <list_exp> }? | <list_exp> ; <arc> = <ident> { ":" <list_exp> }? | <list_exp> ;

【Prologライクリスト処理言語の組み込み関数】

 set_var(name, value)           グローバル変数に値を代入し、1を返します。
 get_var(name)                  グローバル変数から値を取得します。
                                set_var せず get_var すると Exception が発生します。
 ifdef_var(name)                グローバル変数が未定義ならnullが、既定義なら1が返ります。
 undef_var(name)                グローバル変数が既定義なら未定義に戻し、1を返します。

 set_ary(array, idx_ls, value)  配列 array の インデックスリスト idx_ls で指定される要素に値を代入します。
 get_ary(array, idx_ls)         配列 array の インデックスリスト idx_ls で指定される要素から値を取得します。
                                arrayは非nullの任意のオブジェクトで構いません。 
                                インデックスには整数だけでなく文字列・任意リストも使えます。

 attr_grmr(full_parse_tree, attr_grmr, opt)
                                単方向リスト構造のフルパースツリー full_parse_tree から
                                prologライクの双方向ルール attr_grmr で双方向グラフ構造データ graph を生成します。
                                al_symbol_manip("out_syntax_unit", ...)で構文の文法部分のスケルトンが出ます。
 inv_attr_grmr(graph, attr_grmr, syntax, id, opt)
                                双方向グラフ構造データ graph から prologライクの双方向ルール attr_grmr で
                                単方向リスト構造のフルパースツリー full_parse_tree を生成します。
                                al_symbol_manip("out_syntax_unit", ...)で構文の文法部分のスケルトンが出ます。

 write(msg, value)              文字列のメッセージmsgとともにリストデータvalueをプリントします。
 dump(value, print_addr)        グラフデータvalueをプリントします。
                                print_addr に非nullを入れるとノードのアドレスもダンプした文字列を返します。
 stop(message)                  メッセージを出力して実行を中止します。

 gcd(a, b)                      2つの整数 a と b の最大公約数を返します。
 gcd_ex(a, b)                   拡張ユークリッド互除法を行い a*x+b*y=gcdとなるx,y,gcdを
                                 (gcd, x, y)の形式で返します。
 inv_mod_m(a, m)                mod m での a の逆数を返します。
 crt(a, m, b, n)                x = a (mod m), x = b (mod n) の解xを返します。
 factor(a)                      整数aの因子のリストを返します。
 next_prime(p)                  整数pより大きい素数を返します。

 eval_script(script, args)      アルタイルスクリプトを実行します。
                                al_script("eval", script, args); と等価です。
 append(x, y)                   リストxの後にリストyを付け足したリストを返します。
 member(elem, ls)               リストlsに要素elemが含まれている場合は1を含まれて居ない場合はnullを返します。
 length(ls)                     リストlsの長さを返します。
 starts_with(s1, s2)            文字列s1が文字列s2で始まるとき非null、そうでないときnullを返します。
 ends_with(s1, s2)              文字列s1が文字列s2で終わるとき非null、そうでないときnullを返します。

 math( ... )                    数式処理の組み込み関数を呼び出します。参照

 unq_str()                      クイックソートにより文字列比較をアドレス比較で比較できる
                                $$<シーケンス番号>で表されるユニークな文字列を返します。

【拡張Prolog言語処理系の組み込み関数】

 cons(h, t)                    Lispのconsです。
 append(x, y)                  リスト x の後にリスト y を付け足したリストを返します。
 member(x, y)                  リスト y に 要素 x が含まれている場合は 1 を含まれて居ない場合は null を返します。

 write( ... ) == r             引数の値をプリントします。引数の個数は可変です。
                               r が 0 の場合は必ず最後に実行され、Failします。
                               r が 1 の場合は必ず最後に実行され、Successします。
                               r が -1 の場合は引数が定義された段階で実行され、Failします。
                               r が 2 の場合は引数が定義された段階で実行され、Successします。

 dump(graph, print_addr)       グラフデータをツリー状にしてダンプした文字列を返します。
                               print_addr に非nullを入れるとノードのアドレスもダンプした文字列を返します。
                               必ず最後から1つ前に実行されます。

 dst_node(src, attr)           グラフデータのノードsrcから属性attrの出力アーク先のノードを返します。
                               存在しない場合はnullが返ります。

 must_be(value, expect)        valueがリストとしてexpectに等しくない場合Exceptionを発生します。
                               この関数は1を返します。

 var(name, value)              グローバル変数nameから値をvalueにゲット、
                               またはグローバル変数nameに値valueのセットをします。
                               この関数は1を返します。
 undef(name) == r              グローバル変数nameに値を既定義から未定義に戻します。
                               r が 0 の場合、グローバル変数が未定義でも、Successします。
                               r が 1 の場合、グローバル変数が未定義なら、Failします。