Skin: [NORMAL]
[BLUE]
[DOS] [LIGHT]  / コピーするための表示 / 実行
このファイル: /home/web6047/www/cgi-bin/prj/20180728-javascript/callbackを使った例(合理anmからcallback)+batch/batch.js
1 /*
2 スクリプトを分析し、オブジェクト化する。
3 1行ずつステップ実行でき、
4 //anmのある行まで一気に実行することもできる。
5
6 アニメーションにおいて、1つのアニメが終わった後、別のアニメを実行したい。
7 1つのアニメを関数に定義して、次のアニメも関数に定義する。
8 それらの関数を呼び出す関数を定義し、実行する。
9
10 そのためには、まず1行についてアニメ処理となるようにする。
11
12
13
14 サンプル:
15 onloadx() 関数からテキストを抽出し、instructionへ渡し、setInterval。
16 debugprint_recursive()
17
18 本体:
19 InstructionRE 実行環境
20 exec() instructionを実行
21 Instruction テキストを受け取り、プログラムとして解析。
22 analyze() テキストを解析し、階層構造を作成する。
23 escapeBrackets()
24 test()
25 test2();
26
27 */
28
29 function debugprint_recursive( object, indent ) {
30 //check.
31 if( indent == null ) indent = "";
32
33 console.log( "DEC[" + object.declaration + "]\tINST[" + object.instruction + "]\tARG[" + object.argtext + "]" );
34 for( var i = 0; i < object.children.length; i++ ) {
35 indent += "\t";
36 debugprint_recursive( object.children[ i ], indent );
37 indent = indent.substr( 0, indent.length - 1 );
38 }
39 }
40
41
42 //プログラムの命令クラス
43 function Instruction( declaration, instruction, argtext, blocktext, comment ) {
44 /*
45 一般にプログラムの1命令は以下の4項目で成り立っているとここでは考える。
46
47 declaration instracion( argtext ) { blocktext }
48 宣言 命令 引数 ブロック
49
50 単語を以下のように略す。
51 decl inst( argt ) blkt
52
53 例:
54 a = b; //inst decl, argt, blktがない状態
55 if( a == b ) { .. } //inst( argt ) { blkt } declがない状態
56 else { .. } //inst { blkt } decl, argtがない状態
57 test(); //inst( argt ) decl, blktがない状態
58 function test() { .. } //decl inst( argt ) { blkt } すべてそろっている状態
59 var a; //decl inst argt, blktがない状態
60 var a = b; //decl inst argt, blktがない状態
61
62 引数の parts.blocktext は analyze() にとおし、階層構造にして children へ収める。
63 */
64
65
66 this.declaration = declaration;
67 this.instruction = instruction;
68 this.argtext = argtext;
69 this.blocktext = blocktext;
70 this.comment = comment;
71
72 this.children = new Array();
73
74 //ブロック部分を解析
75 if( this.blocktext != null ) this.analyze( this.blocktext );
76
77 }
78 Instruction.prototype.exec = function() {
79 var envs = new Array(); //スタックとして使用
80 var env = {
81 object : this,
82 counter : 0,
83 next : null,
84 parentEnv : null,
85 intoBlk : true,
86 };
87
88 owner = this;
89
90 var func = function() {
91 //envs はこの中でいつまでも有効(クロージャ)
92 //env はこの中でいつまでも有効(クロージャ)
93 loop1: while( 1 ) {
94 //check. ループを抜ける
95 if( ! env.object.commentProcessed && env.object.comment && env.object.comment.match( /anm(\d+)/ ) ) {
96 env.object.commentProcessed = true;
97 var ms = Number( RegExp.$1 );
98 setTimeout( func, ms ); //ループへ戻る
99 break loop1;
100 }
101 else if( ! env.object.commentProcessed && env.object.comment && env.object.comment.match( /suspend/ ) ) {
102 env.object.commentProcessed = true;
103 owner.resume = func;
104 break loop1;
105 }
106
107 env.object.commentProcessed = false;
108
109 //処理実行
110 switch( env.object.instruction ) {
111 //Y 制御 分岐
112 case "if":
113 env.intoBlk = eval( env.object.argtext );
114 //check. ifに対応するelseについて
115 if( env.next && env.next.instruction == "else" ) {
116 env.next.elseCancel = env.intoBlk;
117 }
118 break;
119 case "else":
120 break;
121 //O 制御 繰り返し
122 case "for":
123 if( typeof env.forInit === "undefined" ) {
124 if( env.object.argtext.match( /(.*);(.*);(.*)/ ) ) {
125 env.forInit = RegExp.$1;
126 env.forCond = RegExp.$2;
127 env.forAdd = RegExp.$3;
128 } else {
129 console.log( "syntax erro on for: " + env.object.argtext );
130 }
131 env.forInit = env.forInit.replace( /var\s+/, "env." );
132 eval( env.forInit );
133 } else {
134 with( env ) eval( env.forAdd );
135 }
136 with( env ) env.intoBlk = eval( env.forCond );
137 break;
138 //I 制御 順次
139 default:
140 var script = "";
141 if( env.object.declaration == "function" ) {
142 script += "env.parentEnv.";
143 script += env.object.instruction + " = function( ";
144 script += env.object.argtext + " ) { ";
145 script += env.object.blocktext + " }";
146 env.intoBlk = false;
147 } else if( env.object.declaration == "var" ) {
148 script += "env.";
149 script += env.object.instruction;
150 env.intoBlk = false;
151 } else if( env.object.instruction != null ) {
152 script += env.object.instruction;
153 if( env.object.argtext != null ) script += "(" + env.object.argtext + ")";
154 if( env.object.blocktext != null ) script += "{" + env.object.blocktext + "}";
155 } else {
156 //コメント行などの場合はここに来る。
157 break;
158 }
159
160 //宣言や命令文の実行
161 var allWith = "";
162 for( var j = 1; j < envs.length - 1; j++ ) {
163 allWith += "with( envs[ " + j + " ] ) ";
164 }
165 if( env.parentEnv ) allWith += "with( env.parentEnv ) ";
166
167 eval( allWith + script );
168 }
169
170 //check. 子の走査が終了した?
171 while( env.object.elseCancel || ! env.intoBlk || env.counter == env.object.children.length ) {
172 //check. 最上位である?
173 if( envs.length == 0 ) break loop1;
174 //check. forである
175 if( env.object.instruction == "for" && env.intoBlk ) {
176 env.counter = 0;
177 continue loop1;
178 }
179
180 //親へ戻る
181 env = envs.pop();
182 }
183
184 //次の子へ移る
185 envs.push( env );
186 env = {
187 object : env.object.children[ env.counter++ ],
188 next : env.object.children[ env.counter ],
189 counter : 0,
190 intoBlk : true,
191 parentEnv : env,
192 }
193
194 }//loop1:while
195
196 };//func()
197
198
199 func();
200
201 };
202 Instruction.prototype.analyze = function( text ) {
203 /*
204 text を受け取り、内容を解析して階層構造を見い出し、childrenへ収める。
205 返り値はなし。
206
207 流れ:
208 //1. 不要なタブと改行を削除する。
209 //2. 括弧で囲まれた部分を退避する。(すると入れ子構造がなくなり4項目の取得が行いやすくなる)
210 //3. そのテキストを解析。各行の形状別に4項目を取得
211 //4. 4項目のうち argtext と blocktext について、退避した括弧部分を展開
212 //5. 4項目から新しいinstructionを生成する(階層構造となる)
213 */
214
215
216 //1. 不要なタブと改行を削除する。
217
218 text = text.replace( /^\t+/mg, " " ); //行頭のタブを半角スペース1個にする
219 text = text.replace( /\n/g, ";" ); //改行を半角スペース1個にする
220
221 //2. 括弧で囲まれた部分を退避する。
222 //(すると入れ子構造がなくなり1行1行の4項目の取得が行いやすくなる)
223
224 var res = escapeBrackets( text, "{", "}", "_block_#_;", true );
225 var blocks = res.contents;
226
227 var res = escapeBrackets( res.text, "(", ")", "_kakko_#_" );
228 var kakkos = res.contents;
229
230
231 var text2 = res.text;
232 text2 = text2.replace( /;\s+/mg, ";" );
233 text2 = text2.replace( /^\s+/gm, "" );
234
235 //3. そのテキストを解析。
236
237 var lines = text2.split( /;/ );
238 for( var i = 0; i < lines.length; i++ ) {
239 var line = lines[ i ];
240 //check. 空行はスキップ
241 if( line.match( /^\s*$/ ) ) continue;
242
243 //1命令を構成する4項目
244 var declaration = null;
245 var instruction = null;
246 var argtext = null;
247 var blocktext = null;
248 var comment = null;
249 var tp = null;
250
251 //コメントを処理
252 if( line.match( /\/\// ) ) {
253 line = RegExp.leftContext;
254 comment = RegExp.rightContext;
255 comment = comment.replace( /^\s+|\s+$/g, "" );
256 }
257
258 //各行の形状別に4項目を取得
259 if( line.match( /(var\s+|)(.+=.+?)\((.*)\)/ ) ) { //var a=b() または a=b()
260
261 tp = 1.5;
262 declaration = RegExp.$1;
263 instruction = RegExp.$2;
264 argtext = RegExp.$3;
265
266 } else if( line.match( /(var\s+|)(.+=.+)/ ) ) { //var a=b または a=b
267
268 tp = 1;
269 declaration = RegExp.$1;
270 instruction = RegExp.$2;
271
272
273 } else if( line.match( /(var\s+)(.+)/ ) ) { //var a
274
275 tp = 2;
276 declaration = RegExp.$1;
277 instruction = RegExp.$2;
278
279 } else if( line.match( /(function\s+|)(.+)\((.*)\)(.+)/ ) ) { //function f() .. または if(true) ..など
280
281 tp = 3;
282 declaration = RegExp.$1;
283 instruction = RegExp.$2;
284 argtext = RegExp.$3;
285 blocktext = RegExp.$4;
286
287 } else if( line.match( /(.+)\((.*)\)/ ) ) { //func();
288
289 tp = 4;
290 instruction = RegExp.$1;
291 argtext = RegExp.$2;
292
293 } else if( line.match( /(.*)\s(.*)/ ) ) { //else ..
294
295 tp = 5;
296 instruction = RegExp.$1;
297 blocktext = RegExp.$2;
298
299 } else if( comment != null ) { //コメント行
300
301 } else {
302
303 console.log( "syntax error: " + ": [" + line + "]" );
304 continue;
305
306 }
307
308 //4. 4項目のうち argtext と blocktext について、退避した括弧部分を展開
309 if( argtext != null && argtext.match( /_kakko_(\d+)_/ ) ) {
310 argtext = kakkos[ RegExp.$1 ];
311 }
312
313 if( blocktext != null ) {
314
315 //if() {..}ではなく、if() .. の形で .. の部分で退避された括弧を展開
316 while( blocktext.match( /_kakko_(\d+)_/ ) ) {
317 blocktext = RegExp.leftContext + kakkos[ RegExp.$1 ] + RegExp.rightContext;
318 }
319
320 if( blocktext.match( /_block_(\d+)_/ ) ) {
321 blocktext = blocks[ RegExp.$1 ];
322 }
323 }
324
325 //先頭または末尾のスペースを除去
326 if( declaration != null ) declaration = declaration.replace( /^\s+|\s+$/, "" );
327
328 //5. 4項目から新しい instruction を生成する(階層構造となる)
329 this.children.push( new Instruction( declaration, instruction, argtext, blocktext, comment ) );
330
331 }//for i
332 }
333 function escapeBrackets( text, startBracket, endBracket, identifier, swDelBracket ) {
334 /*
335 テキスト中の括弧を配列へ退避する。
336 処理結果は複数あるので、オブジェクトを返り値として返している。
337
338 usage: var res = escapeBrackets( text, "(", ")", "_kakko_#_" );
339 usage: var res = escapeBrackets( text, "{", "}", "_block_#_", true );
340
341 引数:
342 text 処理したいテキスト
343 startBracket 開始括弧文字指定
344 endBracket 終了括弧文字指定
345 identifier テキスト中の括弧でくくられた部分をこの識別子に置き換える。
346 識別子文字列内の#は通し番号に置き換わる。
347 swDelBracket 括弧でくくられた部分を識別子に置き換えた際、括弧を削除するか。
348 たとえば、
349 if( true ) { .. }
350 のとき、()と{}を処理するとして、
351 {}についてはswDelBracketをtrueにして処理すると、
352 if( _kakko_0 ) {_block_0_}
353 にはならず、
354 if( _kakko_0 ) _block_0_
355 のようになる。
356 つまり、ifの条件部分の括弧()は消したくないが、{}は消したいときに利用する。
357 返り値:
358 res.text
359 引数のtextを処理した結果。
360 text中の括弧でくくられた部分は identifier に置き換わっている。
361 res.contents
362 text中の括弧でくくられた部分を収めた配列。
363 結果のテキスト内の identifier 部分にあたるテキストを収めている。
364 たとえば、
365 res.contents[ 0 ] はテキスト中の1個目の括弧内、
366 res.contents[ 1 ] はテキスト中の2個目の括弧内となる。
367 */
368 var res = {
369 text : "",
370 contents : new Array()
371 };
372
373 var level = 0;
374 var buffer = "";
375 var tail = text;
376 var bracketSearchKey = "[" + startBracket + endBracket + "]";
377
378 while( tail.match( bracketSearchKey ) ) {
379 var bracket = RegExp.lastMatch;
380 var left = RegExp.leftContext;
381 tail = RegExp.rightContext;
382
383 //括弧内の場合は取得し、括弧外(level==0)のときは結果のテキストへ
384 if( level > 0 )
385 buffer += left;
386 else
387 res.text += left;
388
389 //括弧閉じである
390 if( bracket == endBracket ) {
391 level --;
392 //check. 対応する括弧であるとき
393 if( level == 0 ) {
394 var id = identifier.replace( "#", res.contents.length );
395 res.text += id;
396 res.contents.push( buffer );
397 buffer = "";
398 }
399 }
400
401 //括弧そのものは、外側の他の括弧内の場合は取得し、
402 //括弧外(level==0)のときは削除指定でなければ結果のテキストへ
403 if( level > 0 )
404 buffer += bracket;
405 else if( ! swDelBracket )
406 res.text += bracket;
407
408 //括弧開始である
409 if( bracket == startBracket ) {
410 level ++;
411 }
412 }
413 res.text += tail;
414
415 return res;
416 }