source: applications/nimpad/trunk/lib/PEG.php @ 1490

SVN
Revision 1490, 20.0 KB checked in by anatoo, 10 months ago (diff)

0.2ブランチのリビジョン1489,1488の変更をtrunkに取り込んだ

Line 
1<?php
2/**
3 * このクラスは、静的メソッドから様々なパーサやコンテキスト等を生成するのに使われる。
4 *
5 * @package PEG
6 * @author anatoo<anatoo@nequal.jp>
7 * @license http://www.opensource.org/licenses/mit-license.php MIT License
8 * @version $Id: PEG.php 1044 2009-08-01 06:52:10Z anatoo $
9 */
10
11include_once dirname(__FILE__) . '/PEG/IContext.php';
12include_once dirname(__FILE__) . '/PEG/IParser.php';
13
14include_once dirname(__FILE__) . '/PEG/Action.php';
15include_once dirname(__FILE__) . '/PEG/And.php';
16include_once dirname(__FILE__) . '/PEG/Anything.php';
17include_once dirname(__FILE__) . '/PEG/ArrayContext.php';
18include_once dirname(__FILE__) . '/PEG/CallbackAction.php';
19include_once dirname(__FILE__) . '/PEG/Cache.php';
20include_once dirname(__FILE__) . '/PEG/Char.php';
21include_once dirname(__FILE__) . '/PEG/Choice.php';
22include_once dirname(__FILE__) . '/PEG/Curry.php';
23include_once dirname(__FILE__) . '/PEG/EOS.php';
24include_once dirname(__FILE__) . '/PEG/Failure.php';
25include_once dirname(__FILE__) . '/PEG/Lookahead.php';
26include_once dirname(__FILE__) . '/PEG/Many.php';
27include_once dirname(__FILE__) . '/PEG/Memoize.php';
28include_once dirname(__FILE__) . '/PEG/Not.php';
29include_once dirname(__FILE__) . '/PEG/Optional.php';
30include_once dirname(__FILE__) . '/PEG/Ref.php';
31include_once dirname(__FILE__) . '/PEG/Sequence.php';
32include_once dirname(__FILE__) . '/PEG/StringContext.php';
33include_once dirname(__FILE__) . '/PEG/Token.php';
34include_once dirname(__FILE__) . '/PEG/Util.php';
35
36class PEG
37{
38    protected static function parser($val)
39    {
40        return is_string($val) ?  self::token($val) : $val;
41    }
42   
43    protected static function parserArray(Array $arr)
44    {
45        foreach ($arr as &$val) $val = self::parser($val);
46        return $arr;
47    }
48   
49    /**
50     * 引数に応じて適切なPEG_IContextインスタンスを生成する。
51     *
52     * @param string|Array $str
53     * @return PEG_IContext
54     * @see PEG_IContext, PEG_StringContext, PEG_ArrayContext
55     */
56    static function context($val)
57    {
58        if (is_string($val)) return new PEG_StringContext($val);
59        if (is_array($val)) return new PEG_ArrayContext($val);
60        throw new InvalidArgumentException();
61    }
62   
63    /**
64     * PEG_CallbackActionインスタンスを生成する。
65     * PEG::callbackAction($callback, PEG::seq($a, $b, $c)), PEG::callbackAction($callback, $a, $b, $c) は同等
66     *
67     * @param callback $callback
68     * @param $p
69     * @return PEG_CallbackAction
70     * @see PEG_CallbackAction
71     */
72    static function callbackAction($callback, $p)
73    {
74        if (func_num_args() > 2) {
75            $args = func_get_args();
76            array_shift($args);
77            $p = new PEG_Sequence(self::parserArray($args));
78        }
79        return new PEG_CallbackAction($callback, self::parser($p));
80    }
81   
82    /**
83     * PEG_Anythingインスタンスを得る。
84     * このパーサはどのような文字でもパースに成功する
85     *
86     * @return PEG_Anything
87     * @see PEG_Anything
88     */
89    static function anything()
90    {
91        static $obj = null;
92        return $obj ? $obj : $obj = new PEG_Anything;
93    }
94   
95    /**
96     * PEG_Choiceインスタンスを生成する。
97     * このパーサは、パース時に与えられたパーサを順に試していき、初めに成功したパーサの結果をそのまま返す
98     * 全てのパーサが失敗したならば、このパーサは失敗する。
99     *
100     * @return PEG_Choice
101     * @param ...
102     * @see PEG_Choice
103     */
104    static function choice()
105    {
106        return new PEG_Choice(self::parserArray(func_get_args()));
107    }
108   
109    /**
110     * PEG_EOSインスタンスを得る。
111     * このパーサは、パース時に対象が終端に来た、
112     * つまり$aContext->eos() === trueの時の
113     * PEG_IContextインスタンスを与えられたときのみ成功する。
114     *
115     * @return PEG_EOS
116     */
117    static function eos()
118    {
119        static $obj = null;
120        return $obj ? $obj : $obj = new PEG_EOS;
121    }
122   
123    /**
124     * PEG_Notインスタンスを得る。
125     * このパーサは、$pパーサが成功したならば失敗し、$pパーサが失敗したならば成功する。
126     * PEG_Notパーサは文字列を消費しない
127     * PEG::not(PEG::seq($a, $b, $c)), PEG::not($a, $c, $c) は同等
128     *
129     * @param $p
130     * @return PEG_Not
131     */
132    static function not($p)
133    {
134        if (func_num_args() > 1) {
135            $args = func_get_args();
136            $p = new PEG_Sequence(self::parserArray($args));
137        }
138        return new PEG_Not(self::parser($p));
139    }
140   
141    /**
142     * 与えられたパーサが失敗した場合でもfalseを返すパーサを返す
143     * 正規表現でいう"?"
144     * PEG::optional(PEG::seq($a, $b, $c)), PEG::optional($a, $b, $c) は同等。
145     *
146     * @param $p
147     * @return PEG_Parser
148     */
149    static function optional($p)
150    {
151        if (func_num_args() > 1) {
152            $args = func_get_args();
153            $p = new PEG_Sequence(self::parserArray($args));
154        }
155        return new PEG_Optional(self::parser($p));
156    }
157   
158   
159    /**
160     * 複数のパーサを一つにまとめる
161     *
162     * @return PEG_Sequence
163     */
164    static function seq()
165    {
166        return new PEG_Sequence(self::parserArray(func_get_args()));
167    }
168   
169    /**
170     * 与えられたパーサを失敗するまで繰り返し、配列を返すパーサを得る
171     * PEG::many(PEG::seq($a, $b, $c)), PEG::many($a, $b, $c) は同等
172     *
173     * @param $p
174     * @return PEG_Many
175     */
176    static function many($p)
177    {
178        if (func_num_args() > 1) {
179            $args = func_get_args();
180            $p = new PEG_Sequence(self::parserArray($args));
181        }
182        return new PEG_Many(self::parser($p));
183    }
184   
185    /**
186     * 与えられたパーサを失敗するまで繰り返し、配列を返すパーサを得る
187     * パーサが一度も成功しない場合は失敗する
188     * PEG::many1(PEG::seq($a, $b, $c)), PEG::many1($a, $b, $c) は同等
189     *
190     * @param $p
191     * @return PEG_Many1
192     */
193    static function many1($p)
194    {
195        if (func_num_args() > 1) {
196            $args = func_get_args();
197            $p = new PEG_Sequense(self::parserArray($args));
198        }
199        return self::callbackAction(array('PEG_Util', 'cons'), self::seq($p, self::many($p)));
200    }
201   
202    /**
203     * 与えられた文字列をそのまま返すパーサを得る
204     *
205     * @param string $s
206     * @return PEG_Token
207     */
208    static function token($s)
209    {
210        return PEG_Token::get($s);
211    }
212   
213    /**
214     * 与えられたパーサを実行した後、PEG_IContextの読み込み位置を元に戻すパーサを得る
215     * PEG::amp($parser)と同等
216     * PEG::lookahead(PEG::seq($a, $b, $c)), PEG::lookahead($a, $b, $c) は同等
217     * 非推奨。代わりにPEG::ampを使う
218     *
219     * @param $p
220     * @return PEG_Lookahead
221     * @deprecated
222     */
223    static function lookahead($p)
224    {
225        if (func_num_args() > 1) {
226            $args = func_get_args();
227            $p = new PEG_Sequense(self::parserArray($args));
228        }
229        return new PEG_Lookahead(self::parser($p));
230    }
231   
232    /**
233     * PEG::not($parser)と同等
234     * PEG::lookaheadNot(PEG::seq($a, $b, $c)), PEG::lookaheadNot($a, $b, $c) は同等
235     * 非推奨。代わりにPEG::notを使う
236     *
237     * @param $p
238     * @return PEG_Not
239     * @deprecated
240     */
241    static function lookaheadNot($p)
242    {
243        if (func_num_args() > 1) {
244            $args = func_get_args();
245            $p = new PEG_Sequense(self::parserArray($args));
246        }
247        return self::not(self::parser($p));
248    }
249
250    /**
251     *
252     * @return PEG_And
253     */
254    static function andalso()
255    {
256        return new PEG_And(self::parserArray(func_get_args()));
257    }
258
259    /**
260     * 与えたリファレンスをパース時にパーサとして実行するパーサを得る
261     *
262     * @return PEG_Ref
263     */
264    static function ref(&$parser)
265    {
266        return new PEG_Ref($parser);
267    }
268
269    /**
270     * 与えた文字列に含まれる文字にヒットするパーサを得る
271     *
272     * @param string $str
273     * @return PEG_Char
274     */
275    static function char($str)
276    {
277        return new PEG_Char($str);
278    }
279
280    /**
281     * 数字にヒットするパーサを得る
282     *
283     * @return PEG_Char
284     */
285    static function digit()
286    {
287        static $obj = null;
288        return $obj ? $obj : $obj = self::char('0123456789');
289    }
290   
291    /**
292     * 改行にヒットするパーサを得る
293     *
294     * @return PEG_Choice
295     */
296    static function newLine()
297    {
298        static $obj = null;
299        return $obj ? $obj : $obj = self::choice(self::token("\r\n"), self::char("\r\n"));
300    }
301   
302    /**
303     * 行の終わりにヒットするパーサを返す
304     *
305     * @return PEG_Choice
306     */
307    static function lineEnd()
308    {
309        static $p = null;
310        return $p ? $p : $p = self::choice(self::newLine(), self::eos());
311    }
312   
313    /**
314     * アルファベットの大文字にヒットするパーサを得る
315     *
316     * @return PEG_Char
317     */
318    static function upper()
319    {
320        static $obj = null;
321        return $obj ? $obj : $obj = self::char('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
322    }
323   
324    /**
325     * アルファベットの小文字にヒットするパーサを得る
326     *
327     * @return PEG_Char
328     */
329    static function lower()
330    {
331        static $obj = null;
332        return $obj ? $obj : $obj = self::char('abcdefghijklmnopqrstuvwxyz');
333    }
334   
335    /**
336     * アルファベットにヒットするパーサを得る
337     *
338     * @return PEG_Choice
339     */
340    static function alphabet()
341    {
342        static $obj = null;
343        return $obj ? $obj : $obj = self::choice(self::lower(), self::upper());
344    }
345
346    /**
347     *
348     *
349     * @param $key
350     * @param $p
351     * @return PEG_At
352     */
353    static function at($key, $p)
354    {
355        $curry = PEG_Curry::make(array('PEG_Util', 'at'), $key);
356        return self::callbackAction($curry, $p);
357    }
358
359    /**
360     * 与えられたパーサが何か値を返したとき、その値の最初の要素を返すパーサを得る
361     * PEG::first(PEG::seq($a, $b, $c)), PEG::first($a, $b, $c) は同等
362     *
363     * @param $p
364     * @return PEG_At
365     */
366    static function first($p)
367    {
368        if (func_num_args() > 1) {
369            $args = func_get_args();
370            $p = new PEG_Sequense(self::parserArray($args));
371        }
372        return self::at(0, self::parser($p));
373    }
374
375    /**
376     * 与えられたパーサが何か値を返したとき、その値の二番目の要素を返すパーサを得る
377     * PEG::second(PEG::seq($a, $b, $c)), PEG::second($a, $b, $c) は同等
378     *
379     * @param $p
380     * @return PEG_At
381     */
382    static function second($p)
383    {
384        if (func_num_args() > 1) {
385            $args = func_get_args();
386            $p = new PEG_Sequense(self::parserArray($args));
387        }
388        return self::at(1, self::parser($p));
389    }
390
391    /**
392     * 与えられたパーサが何か値を返したとき、その値の三番目の要素を返すパーサを得る
393     * PEG::third(PEG::seq($a, $b, $c)), PEG::third($a, $b, $c) は同等
394     *
395     * @param $p
396     * @return PEG_At
397     */
398    static function third($p)
399    {
400        if (func_num_args() > 1) {
401            $args = func_get_args();
402            $p = new PEG_Sequense(self::parserArray($args));
403        }
404        return self::at(2, self::parser($p));
405    }
406
407    /**
408     * $start, $body, $endの三つのパーサを一つにまとめて、$bodyの返す値のみを返すパーサを得る
409     *
410     * @param $start
411     * @param $body
412     * @param $end
413     * @return PEG_At
414     */
415    static function pack($start, $body, $end)
416    {
417        return self::second(self::seq(self::parser($start), self::parser($body), self::parser($end)));
418    }
419
420    /**
421     * 与えられたパーサが返す配列を平らにするパーサを得る
422     * PEG::flatten(PEG::seq($a, $b, $c)), PEG::flatten($a, $b, $c) と同等
423     *
424     * @param $p
425     */
426    static function flatten($p)
427    {
428        if (func_num_args() > 1) {
429            $args = func_get_args();
430            $p = new PEG_Sequence(self::parserArray($args));
431        }
432        return self::callbackAction(array('PEG_Util', 'flatten'), $p);
433    }
434
435
436    /**
437     * 与えられたパーサがパース時に何を返そうともnullを返すパーサを得る
438     * PEG::seqの引数に使うと、自動的に抜かされる
439     * PEG::drop(PEG::seq($a, $b, $c), PEG::drop($a, $b, $c) は同等
440     *
441     * @param $p
442     * @return PEG_Drop
443     */
444    static function drop($p)
445    {
446        if (func_num_args() > 1) {
447            $args = func_get_args();
448            $p = new PEG_Sequence(self::parserArray($args));
449        }
450        return self::callbackAction(array('PEG_Util', 'drop'), $p);
451    }
452
453    /**
454     * PEG::create('Klass', PEG::seq($a, $b, $c)), PEG::create('Klass', $a, $b, $c) は同等
455     *
456     * @param string $klass
457     * @param $p
458     */
459    static function create($klass, $p)
460    {
461        if (func_num_args() > 2) {
462            $args = func_get_args();
463            array_shift($args);
464            $p = new PEG_Sequence(self::parserArray($args));
465        }
466        $curry = PEG_Curry::make(array('PEG_Util', 'create'), $klass);
467        return self::callbackAction($curry, $p);
468    }
469   
470    /**
471     * 与えれたパーサがパース時に配列を返すとして、その配列をjoinして返すパーサを得る
472     *
473     * @param $p
474     * @param string $glue
475     */
476    static function join($p, $glue = '')
477    {
478        $curry = PEG_Curry::make(array('PEG_Util', 'join'), $glue);
479        return self::callbackAction($curry, $p);
480    }
481
482    /**
483     * 与えられたパーサがパース時に何か返す時、その値をcount()した値を返すパーサを得る
484     *
485     * @param $p
486     * @return PEG_CallbackAction
487     */
488    static function count($p)
489    {
490        return self::callbackAction(array('PEG_Util', 'count'), $p);
491    }
492   
493    /**
494     *
495     *
496     * @param $item
497     * @param $glue
498     * @return PEG_CallbackAction
499     */
500    static function listof($item, $glue)
501    {
502        $parser = self::seq($item, self::many(self::secondSeq($glue, $item)));
503        return self::callbackAction(array('PEG_Util', 'cons'), $parser);
504    }
505
506    /**
507     * 半角空白かタブにヒットするパーサを得る
508     *
509     * @return PEG_Char
510     */
511    static function blank()
512    {
513        static $obj = null;
514        return $obj ? $obj : $obj = self::char(" \t");
515    }
516   
517    /**
518     * PEG::first(PEG::seq($a, $b, ...)), PEG::first($a, $b, $c) 等と同等
519     * 非推奨。PEG::firstを使う
520     *
521     * @return PEG_At
522     * @deprecated
523     */
524    static function firstSeq()
525    {
526        return self::first(new PEG_Sequence(self::parserArray(func_get_args())));
527    }
528   
529    /**
530     * PEG::second(PEG::seq($a, $b, ...)), PEG::second($a, $b, $c) 等と同等
531     * 非推奨。 PEG::secondを使う
532     *
533     * @deprecated
534     * @return PEG_At
535     */
536    static function secondSeq()
537    {
538        return self::second(new PEG_Sequence(self::parserArray(func_get_args())));
539    }
540   
541    /**
542     * PEG::third(PEG::seq($a, $b, ...)), PEG::third($a, $b, $c) 等と同等
543     * 非推奨。PEG::thirdを使う
544     *
545     * @return PEG_At
546     * @deprecated
547     */
548    static function thirdSeq()
549    {
550        return self::third(new PEG_Sequence(self::parserArray(func_get_args())));
551    }
552   
553    /**
554     * 渡されたパーサがパース時に返す値の最後の値を返すパーサを得る
555     * PEG::tail(PEG::seq($a, $b, $c)), PEG::tail($a, $b, $c) は同等
556     *
557     * @param unknown_type $p
558     * @return unknown
559     */
560    static function tail($p)
561    {
562        if (func_num_args() > 1) {
563            $args = func_get_args();
564            $p = new PEG_Sequense(self::parserArray($args));
565        }
566        return self::callbackAction(array('PEG_Util', 'tail'), self::parser($p));
567    }
568   
569    /**
570     * PEG::tail(PEG::seq($a, $b, ...)), PEG::tail($a, $b, $c) 等と同等
571     * 非推奨。PEG::tailを使う
572     *
573     * @return PEG_CallbackAction
574     * @deprecated
575     */
576    static function tailSeq()
577    {
578        return self::tail(new PEG_Sequence(self::parserArray(func_get_args())));
579    }
580   
581    /**
582     * 与えられたパーサを先読みパーサにする
583     * PEG::lookaheadの代わりにこれを使う
584     * PEG::amp(PEG::seq($a, $b, $c), PEG::amp($a, $b, $c) は同等
585     *
586     * @param $p
587     * @return PEG_Lookahead
588     */
589    static function amp($p)
590    {
591        if (func_num_args() > 1) {
592            $args = func_get_args();
593            $p = new PEG_Sequense(self::parserArray($args));
594        }
595        return new PEG_Lookahead(self::parser($p));
596    }
597   
598    /**
599     * PEG::subtract($a, $b, $c), PEG::tailSeq(PEG::not($a), PEG::not($b), $c) は同等
600     *
601     * @param unknown_type $p
602     * @return unknown
603     */
604    static function subtract($p)
605    {
606        $args = func_get_args();
607        array_shift($args);
608        foreach ($args as &$elt) {
609            $elt = self::not(self::parser($elt));
610        }
611        $args[] = self::parser($p);
612        return call_user_func_array(array('PEG', 'tailSeq'), self::parserArray($args));
613    }
614   
615    /**
616     * PEG_Failureインスタンスを返す
617     *
618     * @return PEG_Failure
619     */
620    static function failure()
621    {
622        return PEG_Failure::it();
623    }
624   
625    /**
626     * パーサをメモ化する
627     * PEG::memo(PEG::seq($a, $b, $c)), PEG::memo($a, $b, $c) は同等
628     *
629     * @param $p
630     * @return PEG_Memoize
631     */
632    static function memo($p)
633    {
634        if (func_num_args() > 1) {
635            $args = func_get_args();
636            $p = new PEG_Sequense(self::parserArray($args));
637        }
638        return new PEG_Memoize(self::parser($p));
639    }
640
641    /**
642     * パーサが最初にヒットした時に返した値を返す
643     *
644     * @param PEG_IParser $parser
645     * @param $subject
646     * @return unknown
647     */
648    static function match(PEG_IParser $parser, $subject)
649    {
650        return self::_match($parser, self::context($subject));
651    }
652   
653    static function _match(PEG_IParser $parser, PEG_IContext $context, $need_matching_start = false)
654    {
655        while(!$context->eos()) {
656            $start = $context->tell();
657            $result = $parser->parse($context);
658            $end = $context->tell();
659            if ($result instanceof PEG_Failure) {
660                $context->seek($start + 1);
661            }
662            else {
663                return $need_matching_start ? array($result, $start) : $result;
664            }
665        }
666        return $need_matching_start ? array(self::failure(), null) : self::failure();
667    }
668   
669    /**
670     * パーサがヒットした時の値を全て返す
671     *
672     * @param PEG_IParser
673     * @param string
674     * @return array
675     */
676    static function matchAll(PEG_IParser $parser, $subject)
677    {
678        $context = self::context($subject);
679        $matches = array();
680        while (!$context->eos()) {
681            $result = self::_match($parser, $context);
682            if (!$result instanceof PEG_Failure) {
683                $matches[] = $result;
684            }
685        }
686       
687        return $matches;
688    }
689}
Note: See TracBrowser for help on using the repository browser.