summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--parser/README.md6
-rw-r--r--parser/compiler.go7
-rw-r--r--parser/interpreter_test.go1
-rw-r--r--parser/parse.go54
4 files changed, 57 insertions, 11 deletions
diff --git a/parser/README.md b/parser/README.md
index d46608c..5dcee63 100644
--- a/parser/README.md
+++ b/parser/README.md
@@ -11,13 +11,13 @@ bytecode.
The input of parser is a list of tokens produced by the scanner.
Multiple tokens are processed at once. The minimal set to get
-meaningful results (not an error or nil) is a complete statemement.
+meaningful results (not an error or nil) is a complete statement.
The output of parser is also a list of tokens, to be consummed by
the compiler to produce bytecode. The output tokens set is identical
to the bytecode instructions set except that:
-- code locations may be provided as as labels instead of numerical
+- code locations may be provided as labels instead of numerical
values,
- memory locations for constants and variables may be provided as
symbol names instead of numerical values.
@@ -60,7 +60,7 @@ Go language support:
- [ ] recover statement
- [ ] go statement
- [x] if statement (including else and else if)
-- [ ] for statement
+- [x] for statement
- [ ] switch statement
- [ ] break statement
- [ ] continue statement
diff --git a/parser/compiler.go b/parser/compiler.go
index 5b0ed81..68f0596 100644
--- a/parser/compiler.go
+++ b/parser/compiler.go
@@ -147,6 +147,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
ld := len(c.Data)
c.Data = append(c.Data, lc)
c.addSym(ld, t.Str, lc, symLabel, nil, false)
+ //c.symbols[t.Str] = &symbol{kind: symLabel, value: lc}
}
case lang.JumpFalse:
@@ -157,7 +158,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
t.Beg = len(c.Code)
fixList = append(fixList, t)
} else {
- i = s.value.(int)
+ i = s.value.(int) - len(c.Code)
}
c.Emit(int64(t.Pos), vm.JumpFalse, int64(i))
@@ -168,7 +169,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
t.Beg = len(c.Code)
fixList = append(fixList, t)
} else {
- i = s.value.(int)
+ i = s.value.(int) - len(c.Code)
}
c.Emit(int64(t.Pos), vm.Jump, int64(i))
@@ -191,7 +192,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
}
s, _, ok := c.getSym(label, "")
if !ok {
- return fmt.Errorf("label not found: %v", label)
+ return fmt.Errorf("label not found: %q", label)
}
c.Code[t.Beg][2] = int64(s.value.(int) - t.Beg)
diff --git a/parser/interpreter_test.go b/parser/interpreter_test.go
index ee927a5..124ac66 100644
--- a/parser/interpreter_test.go
+++ b/parser/interpreter_test.go
@@ -63,4 +63,5 @@ var goTests = []struct {
19: {src: "func f(a int) int {return a+2}; f(3) - 2", res: "3"},
20: {src: "func f(a int, b int, c int) int {return a+b-c} ; f(7, 1, 3)", res: "5"},
21: {src: "func f(a, b, c int) int {return a+b-c} ; f(7, 1, 3)", res: "5"},
+ 22: {src: "a := 0; for i := 0; i < 3; i = i+1 {a = a+i}; a", res: "3"},
}
diff --git a/parser/parse.go b/parser/parse.go
index 5f0b643..901ac7d 100644
--- a/parser/parse.go
+++ b/parser/parse.go
@@ -102,6 +102,8 @@ func (p *Parser) ParseStmt(in Tokens) (out Tokens, err error) {
return nil, nil
}
switch t := in[0]; t.Id {
+ case lang.For:
+ return p.ParseFor(in)
case lang.Func:
return p.ParseFunc(in)
case lang.If:
@@ -113,6 +115,53 @@ func (p *Parser) ParseStmt(in Tokens) (out Tokens, err error) {
}
}
+func (p *Parser) ParseFor(in Tokens) (out Tokens, err error) {
+ // TODO: detect invalid code.
+ fc := strconv.Itoa(p.labelCount[p.scope+p.fname])
+ prefix := p.fname + "_for" + fc
+ p.labelCount[p.scope+p.fname]++
+ var init, cond, post, body Tokens
+ pre := in[1 : len(in)-1].Split(lang.Semicolon)
+ switch len(pre) {
+ case 1:
+ cond = pre[0]
+ case 3:
+ init, cond, post = pre[0], pre[1], pre[2]
+ default:
+ return nil, fmt.Errorf("invalild for statement")
+ }
+ p.pushScope("for" + fc)
+ defer p.popScope()
+ if len(init) > 0 {
+ if init, err = p.ParseStmt(init); err != nil {
+ return nil, err
+ }
+ out = init
+ }
+ out = append(out, scanner.Token{Id: lang.Label, Str: prefix + "b"})
+ if len(cond) > 0 {
+ if cond, err = p.ParseExpr(cond); err != nil {
+ return nil, err
+ }
+ out = append(out, cond...)
+ out = append(out, scanner.Token{Id: lang.JumpFalse, Str: "JumpFalse " + prefix + "e"})
+ }
+ if body, err = p.Parse(in[len(in)-1].Block()); err != nil {
+ return nil, err
+ }
+ out = append(out, body...)
+ if len(post) > 0 {
+ if post, err = p.ParseStmt(post); err != nil {
+ return nil, err
+ }
+ out = append(out, post...)
+ }
+ out = append(out,
+ scanner.Token{Id: lang.Goto, Str: "goto " + prefix + "b"},
+ scanner.Token{Id: lang.Label, Str: prefix + "e"})
+ return out, err
+}
+
func (p *Parser) ParseFunc(in Tokens) (out Tokens, err error) {
// TODO: handle anonymous functions (no function name)
// TODO: handle receiver (methods)
@@ -182,13 +231,11 @@ func (p *Parser) ParseIf(in Tokens) (out Tokens, err error) {
if err != nil {
return nil, err
}
- //pre := append(Tokens{{Id: lang.Label, Str: prefix + "_b" + ssc}}, blockout...)
if sc > 0 {
pre = append(pre, scanner.Token{Id: lang.Goto, Str: "goto " + prefix + "_e0"})
}
pre = append(pre, scanner.Token{Id: lang.Label, Str: prefix + "_e" + ssc})
out = append(pre, out...)
-
i--
ifp := in[:i].LastIndex(lang.If)
@@ -198,7 +245,6 @@ func (p *Parser) ParseIf(in Tokens) (out Tokens, err error) {
ssc = strconv.Itoa(sc)
continue
}
-
pre = Tokens{}
var init, cond Tokens
initcond := in[ifp+1 : i+1]
@@ -227,8 +273,6 @@ func (p *Parser) ParseIf(in Tokens) (out Tokens, err error) {
sc++
ssc = strconv.Itoa(sc)
}
- log.Println("prefix:", prefix)
- log.Println("if tokens:", out)
return out, err
}