mighty

The mighty programming language, compiler and tools (WIP)
Log | Files | Refs

commit 550c7d05253cdd6115d417c1c31e510e54222435
parent d4f7bfc0f042898f41dccf822797c2298c9f491c
Author: citbl <citbl@citbl.org>
Date:   Sat, 16 May 2026 18:50:36 +1000

meh parser impl

Diffstat:
Mmtc/lexer/lexer.go | 10++++++++++
Mmtc/main.go | 9++++++---
Amtc/parser/parser.go | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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)) +} + +// +// +// +// +// +// +// +// +//