diff options
Diffstat (limited to 'parser')
| -rw-r--r-- | parser/README.md | 4 | ||||
| -rw-r--r-- | parser/expr.go | 52 | ||||
| -rw-r--r-- | parser/parse.go | 27 |
3 files changed, 47 insertions, 36 deletions
diff --git a/parser/README.md b/parser/README.md index ccf580d..dda3f25 100644 --- a/parser/README.md +++ b/parser/README.md @@ -59,7 +59,7 @@ Go language support: - [x] iota expression - [ ] defer statement - [ ] recover statement -- [ ] range clause +- [x] range clause - [ ] go statement - [x] if statement (including else and else if) - [x] for statement @@ -80,7 +80,7 @@ Go language support: - [x] call expressions - [x] index expressions - [x] selector expressions -- [ ] slice expressions +- [x] slice expressions - [ ] type convertions - [ ] type assertions - [ ] parametric types (generic) diff --git a/parser/expr.go b/parser/expr.go index 1944827..149b5e2 100644 --- a/parser/expr.go +++ b/parser/expr.go @@ -17,9 +17,9 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) { var ops Tokens var ctype string - popop := func() (t scanner.Token) { + popop := func() scanner.Token { l := len(ops) - 1 - t = ops[l] + t := ops[l] ops = ops[:l] if t.Tok.IsLogicalOp() { t.Tok = lang.Label // Implement conditional branching directly. @@ -27,6 +27,15 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) { return t } + // addop adds an operator to the operator stack. + addop := func(t scanner.Token) { + // Operators on stack with a lower precedence are poped out and output first. + for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) { + out = append(out, popop()) + } + ops = append(ops, t) + } + lin := len(in) for i := 0; i < lin; i++ { switch t := in[i]; t.Tok { @@ -47,18 +56,19 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) { case lang.Period: // TODO: fail if next is not an ident. t.Str += in[i+1].Str // Hardwire selector argument. - for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) { - out = append(out, popop()) - } - ops = append(ops, t) + addop(t) i++ // Skip over next ident. + case lang.Next: + out = append(out, t) + + case lang.Range: + ops = ops[:len(ops)-1] // Suppress previous assign or define. + addop(t) + case lang.Colon: t.Str = typeStr - for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) { - out = append(out, popop()) - } - ops = append(ops, t) + addop(t) case lang.Add, lang.And, lang.Assign, lang.Define, lang.Equal, lang.Greater, lang.Less, lang.Mul, lang.Not, lang.Sub, lang.Shl, lang.Shr: if i == 0 || in[i-1].Tok.IsOperator() { @@ -66,30 +76,21 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) { t.Tok = lang.UnaryOp[t.Tok] // FIXME: parsetype for composite if & or * } - for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) { - out = append(out, popop()) - } - ops = append(ops, t) + addop(t) case lang.Land: - for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) { - out = append(out, popop()) - } + addop(t) xp := strconv.Itoa(p.labelCount[p.scope]) p.labelCount[p.scope]++ out = append(out, scanner.Token{Tok: lang.JumpSetFalse, Str: p.scope + "x" + xp}) - t.Str = p.scope + "x" + xp - ops = append(ops, t) + ops[len(ops)-1].Str = p.scope + "x" + xp case lang.Lor: - for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) { - out = append(out, popop()) - } + addop(t) xp := strconv.Itoa(p.labelCount[p.scope]) p.labelCount[p.scope]++ out = append(out, scanner.Token{Tok: lang.JumpSetTrue, Str: p.scope + "x" + xp}) - t.Str = p.scope + "x" + xp - ops = append(ops, t) + ops[len(ops)-1].Str = p.scope + "x" + xp case lang.Ident: s, sc, ok := p.Symbols.Get(t.Str, p.scope) @@ -145,7 +146,8 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) { return out, err } ctype = typ.String() - p.Symbols.Add(symbol.UnsetAddr, ctype, vm.NewValue(typ), symbol.Type, typ, p.funcScope != "") + // p.Symbols.Add(symbol.UnsetAddr, ctype, vm.NewValue(typ), symbol.Type, typ, p.funcScope != "") + p.Symbols.Add(symbol.UnsetAddr, ctype, vm.NewValue(typ), symbol.Type, typ, false) out = append(out, scanner.Token{Tok: lang.Ident, Pos: t.Pos, Str: ctype}) i += n - 1 break diff --git a/parser/parse.go b/parser/parse.go index 46b1724..67d8657 100644 --- a/parser/parse.go +++ b/parser/parse.go @@ -193,25 +193,33 @@ func (p *Parser) parseGoto(in Tokens) (out Tokens, err error) { func (p *Parser) parseFor(in Tokens) (out Tokens, err error) { // TODO: detect invalid code. + var init, cond, post, body, final Tokens fc := strconv.Itoa(p.labelCount[p.scope]) p.labelCount[p.scope]++ - var init, cond, post, body Tokens + breakLabel, continueLabel := p.breakLabel, p.continueLabel + p.pushScope("for" + fc) + p.breakLabel, p.continueLabel = p.scope+"e", p.scope+"b" + defer func() { + p.breakLabel, p.continueLabel = breakLabel, continueLabel + p.popScope() + }() pre := in[1 : len(in)-1].Split(lang.Semicolon) switch len(pre) { case 1: - cond = pre[0] + if in.Index(lang.Range) >= 0 { + init = pre[0] + // cond = Tokens{{Tok: lang.Next, Str: p.scope + "c"}} + // final = Tokens{{Tok: lang.Stop, Str: p.scope + "f"}} + cond = Tokens{{Tok: lang.Next}} + final = Tokens{{Tok: lang.Stop}} + } else { + cond = pre[0] + } case 3: init, cond, post = pre[0], pre[1], pre[2] default: return nil, ErrFor } - breakLabel, continueLabel := p.breakLabel, p.continueLabel - p.pushScope("for" + fc) - p.breakLabel, p.continueLabel = p.scope+"e", p.scope+"b" - defer func() { - p.breakLabel, p.continueLabel = breakLabel, continueLabel - p.popScope() - }() if len(init) > 0 { if init, err = p.parseStmt(init); err != nil { return nil, err @@ -239,6 +247,7 @@ func (p *Parser) parseFor(in Tokens) (out Tokens, err error) { out = append(out, scanner.Token{Tok: lang.Goto, Str: p.scope + "b"}, scanner.Token{Tok: lang.Label, Str: p.scope + "e"}) + out = append(out, final...) return out, err } |
