diff options
| author | Marc Vertes <mvertes@free.fr> | 2023-11-20 15:54:52 +0100 |
|---|---|---|
| committer | Marc Vertes <mvertes@free.fr> | 2023-11-20 15:54:52 +0100 |
| commit | 6a0490257bf235d011004bc303306f617ac6ea31 (patch) | |
| tree | e04160a26f78afaa60c4b18b3b16662d35106d97 | |
| parent | 001ca51323a1a54c9b3db377f0783c330666c480 (diff) | |
parser: add support for unary operators
| -rw-r--r-- | lang/golang/go.go | 1 | ||||
| -rw-r--r-- | lang/token.go | 10 | ||||
| -rw-r--r-- | parser/README.md | 6 | ||||
| -rw-r--r-- | parser/compiler.go | 10 | ||||
| -rw-r--r-- | parser/expr.go | 15 | ||||
| -rw-r--r-- | parser/interpreter_test.go | 4 | ||||
| -rw-r--r-- | vm/vm.go | 4 |
7 files changed, 46 insertions, 4 deletions
diff --git a/lang/golang/go.go b/lang/golang/go.go index 26af4f3..f5a6578 100644 --- a/lang/golang/go.go +++ b/lang/golang/go.go @@ -91,6 +91,7 @@ var GoSpec = &lang.Spec{ "<=": {TokenId: lang.LessEqual, Precedence: 3}, ">=": {TokenId: lang.GreaterEqual, Precedence: 3}, "->": {TokenId: lang.Arrow}, + "!": {TokenId: lang.Not}, "++": {TokenId: lang.Inc, SkipSemi: true}, "--": {TokenId: lang.Dec, SkipSemi: true}, diff --git a/lang/token.go b/lang/token.go index a894c98..4bf9bf2 100644 --- a/lang/token.go +++ b/lang/token.go @@ -116,6 +116,16 @@ const ( EqualSet ) +var UnaryOp = map[TokenId]TokenId{ + Add: Plus, // + + And: Address, // & + Not: Not, // ! + Mul: Deref, // * + Sub: Minus, // - + Tilde: Tilde, // ~ + Xor: BitComp, // ^ +} + func (t TokenId) IsKeyword() bool { return t >= Break && t <= Var } func (t TokenId) IsLiteral() bool { return t >= Char && t <= String } func (t TokenId) IsOperator() bool { return t >= Add && t <= Tilde } diff --git a/parser/README.md b/parser/README.md index eb65dcf..118d9aa 100644 --- a/parser/README.md +++ b/parser/README.md @@ -34,7 +34,7 @@ Go language support: - [ ] export to runtime - [ ] builtin calls (new, make, copy, delete, len, cap, ...) - [ ] out of order declarations -- [ ] arbirtrary precision constants +- [x] arbirtrary precision constants - [x] basic types - [ ] complete numeric types - [x] function types @@ -43,6 +43,7 @@ Go language support: - [x] structures - [ ] embedded structures - [ ] recursive structures +- [ ] literal composite objects - [ ] interfaces - [x] arrays, slices - [ ] maps @@ -70,7 +71,7 @@ Go language support: - [x] label statement - [ ] select statement - [x] binary operators -- [ ] unary operators +- [x] unary operators - [x] logical operators && and || - [ ] assign operators - [x] operator precedence rules @@ -78,6 +79,7 @@ Go language support: - [x] call expressions - [x] index expressions - [x] selector expressions +- [ ] slice expressions - [ ] type convertions - [ ] type assertions - [ ] parametric types (generic) diff --git a/parser/compiler.go b/parser/compiler.go index 41448b7..bdf801b 100644 --- a/parser/compiler.go +++ b/parser/compiler.go @@ -77,6 +77,16 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { push(&symbol{Type: arithmeticOpType(pop(), pop())}) emit(int64(t.Pos), vm.Sub) + case lang.Minus: + emit(int64(t.Pos), vm.Push, 0) + emit(int64(t.Pos), vm.Sub) + + case lang.Not: + emit(int64(t.Pos), vm.Not) + + case lang.Plus: + // Nothing to do. + case lang.Index: emit(int64(t.Pos), vm.Index) diff --git a/parser/expr.go b/parser/expr.go index fa8afa4..207f38b 100644 --- a/parser/expr.go +++ b/parser/expr.go @@ -42,10 +42,21 @@ func (p *Parser) ParseExpr(in Tokens) (out Tokens, err error) { case lang.Int, lang.String: out = append(out, t) vl++ - case lang.Define, lang.Add, lang.Sub, lang.Assign, lang.Equal, lang.Greater, lang.Less, lang.Mul, lang.Land, lang.Lor, lang.Shl, lang.Shr: + case lang.Define, lang.Add, lang.Sub, lang.Assign, lang.Equal, lang.Greater, lang.Less, lang.Mul, lang.Land, lang.Lor, lang.Shl, lang.Shr, lang.Not: + if i == 0 || in[i-1].Id.IsOperator() { + // An operator preceded by an operator or no token is unary. + t.Id = lang.UnaryOp[t.Id] + j := len(out) - 1 + l := out[j] + if p.precedence(l) > 0 { + out = append(out[:j], t, l) + break + } + out = append(out, t) + break + } if vl < 2 { ops = append(ops, t) - break } case lang.ParenBlock: // If the previous token is an arithmetic, logic or assign operator then diff --git a/parser/interpreter_test.go b/parser/interpreter_test.go index 308474c..db9b916 100644 --- a/parser/interpreter_test.go +++ b/parser/interpreter_test.go @@ -65,6 +65,10 @@ func TestExpr(t *testing.T) { {src: "7 == 2 * 3 + 1", res: "true"}, {src: "1 + 3 * 2 == 2 * 3 + 1", res: "true"}, {src: "a := 1 + 3 * 2 == 2 * 3 + 1; a", res: "true"}, + {src: "-2", res: "-2"}, + {src: "-2 + 5", res: "3"}, + {src: "5 + -2", res: "3"}, + {src: "!false", res: "true"}, }) } @@ -37,6 +37,7 @@ const ( Lower // n1 n2 -- cond ; cond = n1 < n2 Loweri // n1 -- cond ; cond = n1 < $1 Mul // n1 n2 -- prod ; prod = n1*n2 + Not // c -- r ; r = !c Pop // v -- Push // -- v Return // [r1 .. ri] -- ; exit frame: sp = fp, fp = pop @@ -69,6 +70,7 @@ var strop = [...]string{ // for VM tracing. Lower: "Lower", Loweri: "Loweri", Mul: "Mul", + Not: "Not", Pop: "Pop", Push: "Push", Return: "Return", @@ -210,6 +212,8 @@ func (m *Machine) Run() (err error) { mem = mem[:sp-1] case Loweri: mem[sp-1] = mem[sp-1].(int) < int(op[2]) + case Not: + mem[sp-1] = !mem[sp-1].(bool) case Pop: mem = mem[:sp-int(op[2])] case Push: |
