commit 550c7d05253cdd6115d417c1c31e510e54222435
parent d4f7bfc0f042898f41dccf822797c2298c9f491c
Author: citbl <citbl@citbl.org>
Date: Sat, 16 May 2026 18:50:36 +1000
meh parser impl
Diffstat:
3 files changed, 196 insertions(+), 3 deletions(-)
diff --git a/mtc/lexer/lexer.go b/mtc/lexer/lexer.go
@@ -27,6 +27,8 @@ const (
Plus
PlusEq
PlusPlus
+ Slash
+ Star
BadToken
)
@@ -133,6 +135,10 @@ func Lex(src string) []Token {
}
case '=':
res = append(res, Token{Eq, src[i : i+1], line, col})
+ case '/':
+ res = append(res, Token{Slash, src[i : i+1], line, col})
+ case '*':
+ res = append(res, Token{Star, src[i : i+1], line, col})
case ',':
res = append(res, Token{Comma, src[i : i+1], line, col})
case '(':
@@ -173,6 +179,10 @@ func (k Kind) String() string {
return "PlusEq"
case PlusPlus:
return "PlusPlus"
+ case Star:
+ return "Star"
+ case Slash:
+ return "Slash"
case Minus:
return "Minus"
case MinusEq:
diff --git a/mtc/main.go b/mtc/main.go
@@ -4,7 +4,8 @@ import (
"fmt"
"os"
- l "mighty/lexer"
+ "mighty/lexer"
+ "mighty/parser"
)
func main() {
@@ -19,6 +20,8 @@ func main() {
panic(err)
}
- tokens := l.Lex(string(data))
- l.Print_tokens(tokens)
+ tokens := lexer.Lex(string(data))
+ lexer.Print_tokens(tokens)
+
+ parser.ParseExpr(tokens)
}
diff --git a/mtc/parser/parser.go b/mtc/parser/parser.go
@@ -0,0 +1,180 @@
+package parser
+
+import (
+ "fmt"
+ "mighty/lexer"
+)
+
+type Expr interface{ expr_node() }
+
+type Ident struct{ Name string }
+
+func (Ident) expr_node() {}
+
+type LitInt struct{ Value string }
+
+func (LitInt) expr_node() {}
+
+type LitStr struct{ Value string }
+
+func (LitStr) expr_node() {}
+
+type Binary struct {
+ Op lexer.Kind
+ Left Expr
+ Right Expr
+}
+
+func (Binary) expr_node() {}
+
+type Call struct {
+ Callee Expr
+ Args []Expr
+}
+
+func (Call) expr_node() {}
+
+type Parser struct {
+ tokens []lexer.Token
+ pos int
+ errs []error
+}
+
+func ParseExpr(tokens []lexer.Token) (Expr, []error) {
+
+ p := Parser{tokens: tokens}
+ expr := p.expr(0)
+
+ return expr, p.errs
+}
+
+func (p *Parser) expr(minPrec int) Expr {
+
+ left := p.postfix()
+
+ for {
+ op := p.peek().Kind
+ prec := precedence(op)
+
+ if prec < minPrec {
+ break
+ }
+
+ p.advance()
+
+ right := p.expr(prec + 1)
+
+ left = Binary{Op: op, Left: left, Right: right}
+ }
+
+ return left
+
+}
+
+func (p *Parser) postfix() Expr {
+ left := p.primary()
+
+ for p.match(lexer.LParen) {
+ var args []Expr
+
+ if !p.check(lexer.RParen) {
+
+ for {
+ args = append(args, p.expr(0))
+ if !p.match(lexer.Comma) {
+ break
+ }
+ }
+ }
+ p.expect(lexer.RParen, "expected ')' after call arguments")
+ left = Call{Callee: left, Args: args}
+
+ }
+ return left
+
+}
+
+func (p *Parser) primary() Expr {
+ tok := p.advance()
+
+ switch tok.Kind {
+
+ case lexer.Ident:
+ return Ident{Name: tok.Value}
+ case lexer.LiteralInt:
+ return LitInt{Value: tok.Value}
+ case lexer.LiteralString:
+ return LitStr{Value: tok.Value}
+ case lexer.LParen:
+ expr := p.expr(0)
+ p.expect(lexer.RParen, "expected ')' after expression")
+ return expr
+ default:
+ p.err(tok, "expected expression")
+ return Ident{Name: "<error>"}
+ }
+}
+
+func precedence(kind lexer.Kind) int {
+ switch kind {
+ case lexer.Plus, lexer.Minus:
+ return 10
+ case lexer.Star, lexer.Slash:
+ return 20
+ default:
+ return -1
+ }
+}
+
+func (p *Parser) peek() lexer.Token {
+
+ if p.pos >= len(p.tokens) {
+ return p.tokens[len(p.tokens)-1]
+ }
+
+ return p.tokens[p.pos]
+}
+
+func (p *Parser) advance() lexer.Token {
+
+ tok := p.peek()
+ if p.pos < len(p.tokens) {
+ p.pos++
+ }
+ return tok
+}
+
+func (p *Parser) check(kind lexer.Kind) bool {
+ return p.peek().Kind == kind
+}
+
+func (p *Parser) match(kind lexer.Kind) bool {
+ if !p.check(kind) {
+ return false
+ }
+ p.advance()
+ return true
+}
+
+func (p *Parser) expect(kind lexer.Kind, msg string) lexer.Token {
+ if p.check(kind) {
+ return p.advance()
+ }
+
+ p.err(p.peek(), msg)
+ return lexer.Token{Kind: kind}
+}
+
+func (p *Parser) err(tok lexer.Token, msg string) {
+ p.errs = append(p.errs, fmt.Errorf("%d:%d %s", tok.Line, tok.Col, msg))
+}
+
+//
+//
+//
+//
+//
+//
+//
+//
+//