PLY

parser.out

example/calc/calc.py を実行すると、parser.out, parsetab.py というものが生成されるparser.out Unused terminals: Grammar Rule 1 statement -> NAME = expression Rule 2 statement -> expression Rule 3 expression -> expression + expression Rule 4 …

開始記号の指定

start で指定 #!/usr/bin/env python import ply.lex as lex tokens = ( 'A', 'B', ) t_A = r'A' t_B = r'B' t_ignore = " \t" def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) lex.lex() import ply.yacc as yacc start = 'i…

空規則?の扱い

#!/usr/bin/env python import ply.lex as lex tokens = ( 'A', ) t_A = r'A' t_ignore = " \t" def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) lex.lex() import ply.yacc as yacc def p_input(p): '''input : | A''' if (l…

単純なものを試す。

literals では、文字列長2以上の文字列は指定できないらしい。 まあ、考えてみれば、「literals = "+-*/"」とも書けるので当然か?でも不便? #!/usr/bin/env python import ply.lex as lex tokens = ( 'A', ) literals = ['=='] t_A = r'a' def t_error(t):…

単純なものを試す。ルールの書きかた、まとめ方

#!/usr/bin/env python import ply.lex as lex tokens = ( 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', ) t_A = r'A' t_B = r'B' t_C = r'C' t_D = r'D' t_E = r'E' t_F = r'F' t_a = r'a' t_b = r'b' t_c = r'c' t_ignore = " \t" def t_error(t): print…

単純なものを試す。リテラルまわりの挙動

#!/usr/bin/env python import ply.lex as lex tokens = ( 'OTHERS', 'newline', ) literals = ['a', 'b', 'c'] t_newline = r'\n' t_OTHERS = r'[^a-c]' t_ignore = " \t" def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) le…

単純なものを試す。選択

#!/usr/bin/env python import ply.lex as lex tokens = ( 'A', 'B', 'C', 'D', 'E', 'F', ) t_A = r'a' t_B = r'b' t_C = r'c' t_D = r'd' t_E = r'e' t_F = r'f' t_ignore = " \t" def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.s…

Parsing 簡単な場合

#!/usr/bin/env python import ply.lex as lex tokens = ( 'A', 'B', 'newline', ) t_A = r'a' t_B = r'b' t_newline = r'\n' def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) lex.lex() import ply.yacc as yacc def p_input…

ruby で Lexer もどきを書き racc で使用

PLY を真似て ruby で Lexer もどきを書いてみた。 racc で使えるように改造した。Lexer もどき LexToken = Struct.new(:type, :value, :lineno, :lexpos) class Lex def initialize(tokens) @tokens = tokens @lineno = 1 @lexpos = 0 end def input(data) …

ruby で Lexer もどきを書いてみる

PLY を真似て ruby で Lexer もどきを書いてみた。 lex 処理は、『Rubyを256倍使うための本 無道編』由来(コード自体は全然違うけど)。 LexToken = Struct.new(:type, :value, :lineno, :lexpos) class Lex def initialize(tokens) @tokens = tokens @lineno…

lex を試す。re.compile() へのオプション

「lex.lex(reflags=)」で指定する #!/usr/bin/env python import ply.lex as lex import re tokens = ( 'A', 'PLUS', ) t_A = r'a' t_PLUS = r'\+' def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) lexer = lex.lex(reflags=r…

lex を試す。C のコメントっぽいの

マニュアルの記述にちょっと追加して #!/usr/bin/env python import ply.lex as lex tokens = ( 'A', 'PLUS', 'CCODE', 'string', 'char', ) t_A = r'a' t_PLUS = r'\+' t_ANY_ignore = " \t\n" def t_error(t): print "Illegal character '%s'" % t.value[0…

lex を試す。状態の管理

begin でなく、push_state, pop_state を使うこともできる。 #!/usr/bin/env python import ply.lex as lex states = ( ('foo', 'exclusive'), ) tokens = ( 'A', 'PLUS', ) t_A = r'a' t_ANY_PLUS = r'\+' t_ANY_ignore = ' \t\n' t_foo_A = r'b' def t_beg…

lex を試す。複数の状態を指定

「t_foo_INITIAL_PLUS = r'\+'」のように複数の状態「foo」「INITIAL」(初期状態)を指定できるようだ。 ('exclusive' でも全条件だったら ANY を使えば良いだけだけど) #!/usr/bin/env python import ply.lex as lex states = ( ('foo', 'exclusive'), ) tok…

lex を試す。状態 inclusive, exclusive

Flex のマニュアルの例を使ってFlex のマニュアルで言うところの包含的スタート状態(%s) #!/usr/bin/env python import ply.lex as lex states = ( ('state1', 'inclusive'), ) tokens = ( 'ONE', 'THREE', ) def t_state1_ONE(t): r'one' print "two" retur…

lex を試す。状態

機能の詳細はともかく、とりあえず試してみる #!/usr/bin/env python import ply.lex as lex states = ( ('foo', 'exclusive'), ) tokens = ( 'A', 'PLUS', ) t_A = r'a' t_ANY_PLUS = r'\+' t_ANY_ignore = ' \t\n' t_foo_A = r'b' def t_begin_foo(t): r's…

lex を試す。内部変数

#!/usr/bin/env python import ply.lex as lex tokens = ( 'A', 'PLUS', ) t_A = r'a' t_PLUS = r'\+' def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) lexer = lex.lex() lexer.input("a+a") print dir(lexer) print lexer.l…

lex を試す。Lexer の複製

マニュアルによると、こういうこと? クラスで定義していないときは、以下のようにやれば良い。 これは、lex() を呼んで再度ルールなどを構築し直すよりも速い。 lexer = lex.lex() ... newlexer = lexer.clone() 一方、クラス定義した場合は、ちょっと考え…

lex を試す。状態をどう持つか?

グローバル変数。複数の lexer に対応できない t.lexer.var のような lex 以外の prefix を持つ lexer のアトリビュート(var がアトリビュート名)。嫌われる場合あり。なんで? lexer クラスを作り、そのインスタンス変数

lex を試す。複数のクラスを記述

一つのファイルに複数のクラスを記述 #!/usr/bin/env python import ply.lex as lex class MyLexer1: tokens = ( 'A', 'PLUS', ) t_A = r'a' t_PLUS = r'\+' def t_error(self,t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) # Build the…

lex を試す。クラスとして記述

まんま #!/usr/bin/env python import ply.lex as lex class MyLexer: # List of token names. This is always required tokens = ( 'NUMBER', 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'LPAREN', 'RPAREN', ) # Regular expression rules for simple tokens t_…

lex を試す。複数の lexer 再び

(複数の lexer に限った話ではないけど) d:id:noritsugu:20080309:parser で自分なりにやっていたが、マニュアルにも記述があった。 ルールだけ書けば良かったようだ。 lexer ルール 1 tokens = ( 'A', 'PLUS', ) t_A = r'a' t_PLUS = r'\+' def t_error(t):…

lex を試す。lex.lex(optimize=1)

#!/usr/bin/env python import ply.lex as lex tokens = ( 'A', 'PLUS', ) t_A = r'a' t_PLUS = r'\+' def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) lex.lex(optimize=1) lex.input("a+a") while 1: tok = lex.token() if …

lex を試す。__doc__ を直接書き換え

#!/usr/bin/env python import ply.lex as lex digit = r'([0-9])' nondigit = r'([_A-Za-z])' identifier = r'(' + nondigit + r'(' + digit + r'|' + nondigit + r')*)' reserved = { 'if' : 'IF', 'then' : 'THEN', 'else' : 'ELSE', 'while' : 'WHILE', …

lex を試す。@TOKEN decorator

python 2.4 (以上)でないとダメ #!/usr/bin/env python import ply.lex as lex from ply.lex import TOKEN digit = r'([0-9])' nondigit = r'([_A-Za-z])' identifier = r'(' + nondigit + r'(' + digit + r'|' + nondigit + r')*)' reserved = { 'if' : 'IF…

lex を試す。エラー処理

「t.lexer.skip(1)」は一文字(トークン?)捨てるという意味のようだ lexer でエラーなんてあって良いのか分からないのだけど。

lex を試す。literals

#!/usr/bin/env python import ply.lex as lex tokens = ( 'A', ) literals = [ '+','-','*','/' ] t_A = r'a' def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer.skip(1) lex.lex() lex.input("a+a") while 1: tok = lex.token() if no…

lex を試す。column の計算

特別には用意されていないから、lexpos から計算しろとのこと。 まあ、たしかにエラー表示でも行番号だけで、column は使わないか

lex を試す。行情報の更新

#!/usr/bin/env python import ply.lex as lex tokens = ( 'A', 'PLUS', ) t_A = r'a' t_PLUS = r'\+' def t_newline(t): r'\n+' t.lexer.lineno += len(t.value) #t.lexer.lexpos = 0 def t_error(t): print "Illegal character '%s'" % t.value[0] t.lexer…

lex を試す。トークンを捨てる

「t_ignore_」という名前を使うと、自動的に捨てるらしい #!/usr/bin/env python import ply.lex as lex tokens = ( 'A', 'PLUS', ) t_A = r'a' t_PLUS = r'\+' t_ignore_COMMENT = r'\#.*' def t_error(t): print "Illegal character '%s'" % t.value[0] t.…