20 posts tagged “rubyex”
このURLへ行ってください: http://github.com/celtic/rubyex has all you need.
まあ、大学がもう一度始まりましたから、RubyExのついてにことができません!暇な時が全然ありません、いつも忙しくてはらはらします!それに、日本語の学科でもう1年間上のレベルに入ることになりましたから、もっともっと忙しくなりましたぁ。( 私は言うまでもなく日本語が上手じゃないからです)
これでもね、今は学期中間休みです!一週間だけですけど、ちょっとできるだけしよう。RubyExのVMが少し務まるのはゴールです。
Well, university started once more, so I've been unable to work on RubyEx! I've had no time to myself at all, always busy and nervous! In addition, I moved up an extra year in my Japanese studies, so I've been more and more busy. (as I am clearly not so great at Japanese)
However, now it's mid-semester break! I get a week only, but I'll do a bit of what I can. My goal is to have RubyEx's VM working a bit as it should.
Read instruction: CALL p (1 arg/s)
argument: STACK: pop() -- new stack size: 2
type=3
Read instruction: END
Read instruction: PUSH INTEGER_LITERALSTACK: push() -- new stack size: 3Read instruction: TARGET_CALL_BLOCK upto (1 arg/s)
STACK: pop() -- new stack size: 2
STACK: pop() -- new stack size: 1
argument: STACK: pop() -- new stack size: 0
type=3
Read instruction: END
Read instruction: PUSH INTEGER_LITERALSTACK: push() -- new stack size: 1Read instruction: TARGET_CALL_BLOCK upto (1 arg/s)
STACK: pop() -- new stack size: 0
STACK: pop() -- new stack size: ffffffff
argument: STACK: pop() -- new stack size: fffffffe
type=3
This is what happens when you write a VM. You get a stack with length 0xfffffffe.
RubyExは今バイトコードをアウトプットします!
Now RubyEx outputs byte-code!
もちろん、これでは読めないだけど。。次のはmoduleとprogramのソフトパッケージはバイトがコードを読まされる。celtic@sohma:~/code/linux/rubyex/translator$ cat test.rb
puts "Hi there."
a = who_knows("Joe", 42 - (9 * sin(12)))
a.each do
el { joe {}; q {} }
endceltic@sohma:~/code/linux/rubyex/translator$ ./parser -b < test.rb
puts Hi there.
a who_knowsJoe *- * sin
aeach el joe q
Of course, here you can't read it... next will be getting the 'module' and 'program' packages to read the byte-code!
簡単にデバッグのために、今サンプルパーサのアウトプットはコードです!たとえば:
For easier debugging, the sample parser's output is now code! For example:
かっこいい〜a(b(c{t}){d}).q{e{h{|a|b}}}
Program: 1 expression(s).
a(b(c {t}) {d}).q {e {h {|a| b}}}
Cool~
a(b).c
Program: 1 expression(s).
FuncCallExpr: Expr.c
FuncCallExpr: a(arguments)
IdentifierExpr: b
簡単!
Simple!
a(b, c).d
a(b).c
Program: 2 expression(s).
FuncCallExpr: Expr.d
FuncCallExpr: a(arguments)
IdentifierExpr: b
IdentifierExpr: c
FuncCallExpr: a(arguments)
FuncCallExpr: Expr.c
IdentifierExpr: b
"a(b, c).d"は正しくパースして、"a(b).c"が間違えるの!?パーサトレースするときだ!!
"a(b, c).d" is correctly parsed, and "a(b).c" is not?! Parser trace time!!
"a(b)"でもパースのは:
Even when parsing "a(b)", we get:
見てねぇ。"(b)"のパースした後で"b"にシンプリファイしたら、まだ"a b"です。同じです。でもね、"a(b).c"は"a b.c"になって、速く間違える!Damn. ==Shifting token ')' ()
Entering state 53
Reducing stack by rule 9 (line 60):
$1 = token '(' ()
$2 = nterm expr ()
$3 = token ')' ()
-> $$ = nterm expr ()
Have a look. After parsing "(b)", it's simplified, though it's still "a b" - the same - but then "a(b).c" becomes "a b.c", quickly becoming incorrect! Damn. ==
直すときだ。。。。
Time to fix...
Here's the problem I'm having right now:
- "a b.c" correctly parses as "a(b.c)"
- "a(b).c" also - incorrectly - parses as "a(b.c)"
Since I'm relatively a novice at building parsers (this is my first), I'll try to step through my muddled fixing of the situation. I'm looking at the output of the various parser states that bison's given me, and here, I think, is the s/r conflict that needs to be fixed: (correct me if I'm wrong)
As it says, it's state 29. Hello, state 29. First the matching rules are listed. Anything after the `expr:' or `|' is part of the rule that's matched, and the lone `.' indicates where it matches.. for example:
- expr . '.' funccall -- we've just seen an expr, and there's a full stop followed by a function call ahead
- expr . '*' expr -- we just saw an expr, and we're seeing an asterisk and another expr afterward.
- '-' expr . -- we just saw a negation operator and an expr (what lies ahead is irrelevant)
The evil here is that '.' is also shifting. That means instead of reducing expr into a funccall or whatever we like, we continue to shift expr.something. We keep shifting until we reduce, and that'll be when we see something stupid like (b).c, and that reduces nicely into an expr of its own, and then expr expr will reduce into funccall! Mayhem!
The important thing to notice here is that it's also detected that we could reduce '.'. By default, bison handles shift/reduce conflicts by shifting, thus capturing the greatest "area", and associating elements as closely as possible. It shows that the reduce is not being used by surrounding it in brackets. Let's have a quick survey of the other rules:
Here's state 40. We can see that, depending on what happens next, it shifts. Remember kids, that expr on the left is only the most recent expr, since we didn't reduce earlier! That is to say, a(b) was never reduced into one expr, so it still exists as two; a, (b), and thus (b) is the expr before the '.' in these rules.
To back up a little, I don't think state 29 is the cause of all my problems, but similar states elsewhere which don't reduce first are a headache.
We're starting to become more useful, with the addition of block arguments. Here's a sample bit of code that parses nicely:
Just to analyse the parse a little:fictional do |exp, evaller|
exp.split(" ").map {|p| evaller.call(p)}
end
Program: 1 expression(s).
FuncCallExpr: fictional(arguments) { BlockExpr }
BlockExpr: |DefListExpr| 1 expression(s).
DefListExpr: 2 identifier(s).
IdentifierExpr: exp
IdentifierExpr: evaller
FuncCallExpr: Expr.split(arguments)
IdentifierExpr: exp
FuncCallExpr: Expr.map(arguments) { BlockExpr }
LiteralTypedExpr<Ss>:
BlockExpr: |DefListExpr| 1 expression(s).
DefListExpr: 1 identifier(s).
IdentifierExpr: p
FuncCallExpr: Expr.call(arguments)
IdentifierExpr: evaller
IdentifierExpr: p
- We have one FuncCallExpr, calling "fictional" (no arguments are specified in the tree, if you look carefully) with a block. I should probably make it not show '(arguments)' if there are none. :)
- Follows the BlockExpr, with a DefListExpr of block arguments, and an expression.
- The DefListExpr has two identifiers: exp, evaller. These are the block arguments, hello!
- Following the DefListExpr in the output of the BlockExpr is that 1 expression(s), a FuncCallExpr.
- This FuncCallExpr is a call to the `split' method of some Expr.
- That Expr is an identifier, exp.
- Under construction.
celtic@sohma:~/code/linux/rubyex/translator$ ./parser
puts -3
puts - 3
Program: 2 expression(s).
FuncCallExpr: puts(arguments)
LiteralTypedExpr<i>: -3
FuncCallExpr: Expr.-(arguments)
IdentifierExpr: puts
LiteralTypedExpr<i>: 3
celtic@sohma:~/code/linux/rubyex/translator$
正しい結果です。もっと一つの問題な場合だけあります:
It's the correct result. We've just got one more problem case remaining:
"puts-3"はまだ"puts(-3)"と同じくパースしています。puts-3
Program: 1 expression(s).
FuncCallExpr: puts(arguments)
LiteralTypedExpr<i>: -3
"puts-3" is still being parsed like "puts(-3)".
RubyExのlexerは今"-3"が読んだらLiteralTypedExpr<int>(-3)をemitします。以前は"3.-@"、でもこうはもっと柔軟だと思う。
RubyEx's lexer is now reading "-3" and emitting LiteralTypedExpr<int>(-3). Earlier it was emitting "3.-@", but this way is probably more flexible.
