mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-18 23:13:29 +00:00
begin binary expressions
This commit is contained in:
parent
3c3c1fc880
commit
1e68083aad
@ -51,8 +51,12 @@ func (f *Function) Emit() string {
|
|||||||
type Opcode string
|
type Opcode string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Mov Opcode = "mov"
|
Mov Opcode = "mov"
|
||||||
Ret Opcode = "ret"
|
Ret Opcode = "ret"
|
||||||
|
Add Opcode = "add"
|
||||||
|
Sub Opcode = "sub"
|
||||||
|
Imull Opcode = "imul"
|
||||||
|
Idiv Opcode = "idiv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Instruction struct {
|
type Instruction struct {
|
||||||
@ -113,3 +117,9 @@ type Imm int64
|
|||||||
func (i Imm) OperandString(size OperandSize) string {
|
func (i Imm) OperandString(size OperandSize) string {
|
||||||
return fmt.Sprintf("%d", i)
|
return fmt.Sprintf("%d", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Stack int64
|
||||||
|
|
||||||
|
func (s Stack) OperandString(size OperandSize) string {
|
||||||
|
return fmt.Sprintf("rbp(%d)", s)
|
||||||
|
}
|
||||||
|
36
ast/ast.go
36
ast/ast.go
@ -73,3 +73,39 @@ type IntegerExpression struct {
|
|||||||
func (ie *IntegerExpression) expressionNode() {}
|
func (ie *IntegerExpression) expressionNode() {}
|
||||||
func (ie *IntegerExpression) TokenLiteral() string { return ie.Token.Literal }
|
func (ie *IntegerExpression) TokenLiteral() string { return ie.Token.Literal }
|
||||||
func (ie *IntegerExpression) String() string { return ie.Token.Literal }
|
func (ie *IntegerExpression) String() string { return ie.Token.Literal }
|
||||||
|
|
||||||
|
//go:generate stringer -type=BinaryOperator
|
||||||
|
type BinaryOperator int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Add BinaryOperator = iota
|
||||||
|
Subtract
|
||||||
|
Multiply
|
||||||
|
Divide
|
||||||
|
)
|
||||||
|
|
||||||
|
func (bo BinaryOperator) SymbolString() string {
|
||||||
|
switch bo {
|
||||||
|
case Add:
|
||||||
|
return "+"
|
||||||
|
case Subtract:
|
||||||
|
return "-"
|
||||||
|
case Multiply:
|
||||||
|
return "*"
|
||||||
|
case Divide:
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
return "<INVALID BINARY OPERATOR>"
|
||||||
|
}
|
||||||
|
|
||||||
|
type BinaryExpression struct {
|
||||||
|
Token token.Token // The operator
|
||||||
|
Lhs, Rhs Expression
|
||||||
|
Operator BinaryOperator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (be *BinaryExpression) expressionNode() {}
|
||||||
|
func (be *BinaryExpression) TokenLiteral() string { return be.Token.Literal }
|
||||||
|
func (be *BinaryExpression) String() string {
|
||||||
|
return fmt.Sprintf("%s %s %s", be.Lhs, be.Operator, be.Rhs)
|
||||||
|
}
|
||||||
|
26
ast/binaryoperator_string.go
Normal file
26
ast/binaryoperator_string.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Code generated by "stringer -type=BinaryOperator"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package ast
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[Add-0]
|
||||||
|
_ = x[Subtract-1]
|
||||||
|
_ = x[Multiply-2]
|
||||||
|
_ = x[Divide-3]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _BinaryOperator_name = "AddSubtractMultiplyDivide"
|
||||||
|
|
||||||
|
var _BinaryOperator_index = [...]uint8{0, 3, 11, 19, 25}
|
||||||
|
|
||||||
|
func (i BinaryOperator) String() string {
|
||||||
|
if i < 0 || i >= BinaryOperator(len(_BinaryOperator_index)-1) {
|
||||||
|
return "BinaryOperator(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _BinaryOperator_name[_BinaryOperator_index[i]:_BinaryOperator_index[i+1]]
|
||||||
|
}
|
15
cmd/cmd.go
15
cmd/cmd.go
@ -23,29 +23,28 @@ type Arguments struct {
|
|||||||
OnlyEmitAsm bool
|
OnlyEmitAsm bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefix writer writes a prefix befor a call to an other writer
|
// Prefix writer writes a prefix before each new line from another io.Writer
|
||||||
// This Prefix is written befor each new line
|
type PrefixWriter struct {
|
||||||
type prefixWriter struct {
|
|
||||||
output io.Writer
|
output io.Writer
|
||||||
outputPrefix []byte
|
outputPrefix []byte
|
||||||
outputPrefixWritten bool
|
outputPrefixWritten bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPrefixWriter(output io.Writer, prefix []byte) *prefixWriter {
|
func NewPrefixWriter(output io.Writer, prefix []byte) *PrefixWriter {
|
||||||
return &prefixWriter{
|
return &PrefixWriter{
|
||||||
output: output,
|
output: output,
|
||||||
outputPrefix: prefix,
|
outputPrefix: prefix,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPrefixWriterString(output io.Writer, prefix string) *prefixWriter {
|
func NewPrefixWriterString(output io.Writer, prefix string) *PrefixWriter {
|
||||||
return &prefixWriter{
|
return &PrefixWriter{
|
||||||
output: output,
|
output: output,
|
||||||
outputPrefix: []byte(prefix),
|
outputPrefix: []byte(prefix),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *prefixWriter) Write(p []byte) (n int, err error) {
|
func (w *PrefixWriter) Write(p []byte) (n int, err error) {
|
||||||
|
|
||||||
toWrites := bytes.SplitAfter(p, []byte{'\n'})
|
toWrites := bytes.SplitAfter(p, []byte{'\n'})
|
||||||
|
|
||||||
|
3
go.mod
3
go.mod
@ -1,3 +1,6 @@
|
|||||||
module robaertschi.xyz/robaertschi/tt
|
module robaertschi.xyz/robaertschi/tt
|
||||||
|
|
||||||
go 1.23.4
|
go 1.23.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
)
|
||||||
|
6
go.sum
Normal file
6
go.sum
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||||
|
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||||
|
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
@ -71,6 +71,14 @@ func (l *Lexer) NextToken() token.Token {
|
|||||||
tok = l.newToken(token.OpenParen)
|
tok = l.newToken(token.OpenParen)
|
||||||
case ')':
|
case ')':
|
||||||
tok = l.newToken(token.CloseParen)
|
tok = l.newToken(token.CloseParen)
|
||||||
|
case '+':
|
||||||
|
tok = l.newToken(token.Plus)
|
||||||
|
case '-':
|
||||||
|
tok = l.newToken(token.Minus)
|
||||||
|
case '*':
|
||||||
|
tok = l.newToken(token.Asterisk)
|
||||||
|
case '/':
|
||||||
|
tok = l.newToken(token.Slash)
|
||||||
case -1:
|
case -1:
|
||||||
tok.Literal = ""
|
tok.Literal = ""
|
||||||
tok.Type = token.Eof
|
tok.Type = token.Eof
|
||||||
|
@ -12,11 +12,18 @@ import (
|
|||||||
type precedence int
|
type precedence int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LOWEST precedence = iota
|
PrecLowest precedence = iota
|
||||||
SUM
|
PrecSum
|
||||||
PRODUCT
|
PrecProduct
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var precedences = map[token.TokenType]precedence{
|
||||||
|
token.Plus: PrecSum,
|
||||||
|
token.Minus: PrecSum,
|
||||||
|
token.Asterisk: PrecProduct,
|
||||||
|
token.Slash: PrecProduct,
|
||||||
|
}
|
||||||
|
|
||||||
type ErrorCallback func(token.Token, string, ...any)
|
type ErrorCallback func(token.Token, string, ...any)
|
||||||
type prefixParseFn func() ast.Expression
|
type prefixParseFn func() ast.Expression
|
||||||
type infixParseFn func(ast.Expression) ast.Expression
|
type infixParseFn func(ast.Expression) ast.Expression
|
||||||
@ -40,6 +47,10 @@ func New(l *lexer.Lexer) *Parser {
|
|||||||
p.registerPrefixFn(token.Int, p.parseIntegerExpression)
|
p.registerPrefixFn(token.Int, p.parseIntegerExpression)
|
||||||
|
|
||||||
p.infixParseFns = make(map[token.TokenType]infixParseFn)
|
p.infixParseFns = make(map[token.TokenType]infixParseFn)
|
||||||
|
p.registerInfixFn(token.Plus, p.parseBinaryExpression)
|
||||||
|
p.registerInfixFn(token.Minus, p.parseBinaryExpression)
|
||||||
|
p.registerInfixFn(token.Asterisk, p.parseBinaryExpression)
|
||||||
|
p.registerInfixFn(token.Slash, p.parseBinaryExpression)
|
||||||
|
|
||||||
p.nextToken()
|
p.nextToken()
|
||||||
p.nextToken()
|
p.nextToken()
|
||||||
@ -77,10 +88,14 @@ func (p *Parser) peekTokenIs(tt token.TokenType) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPrecedence(tt token.TokenType) precedence {
|
func getPrecedence(tt token.TokenType) precedence {
|
||||||
switch tt {
|
if prec, ok := precedences[tt]; ok {
|
||||||
default:
|
return prec
|
||||||
return LOWEST
|
|
||||||
}
|
}
|
||||||
|
return PrecLowest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) curPrecedence() precedence {
|
||||||
|
return getPrecedence(p.curToken.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) peekPrecedence() precedence {
|
func (p *Parser) peekPrecedence() precedence {
|
||||||
@ -161,7 +176,7 @@ func (p *Parser) parseDeclaration() ast.Declaration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.nextToken()
|
p.nextToken()
|
||||||
expr := p.parseExpression(LOWEST)
|
expr := p.parseExpression(PrecLowest)
|
||||||
if !p.expectPeek(token.Semicolon) {
|
if !p.expectPeek(token.Semicolon) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -212,3 +227,26 @@ func (p *Parser) parseIntegerExpression() ast.Expression {
|
|||||||
int.Value = value
|
int.Value = value
|
||||||
return int
|
return int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseBinaryExpression(lhs ast.Expression) ast.Expression {
|
||||||
|
var op ast.BinaryOperator
|
||||||
|
switch p.curToken.Type {
|
||||||
|
case token.Plus:
|
||||||
|
op = ast.Add
|
||||||
|
case token.Minus:
|
||||||
|
op = ast.Subtract
|
||||||
|
case token.Asterisk:
|
||||||
|
op = ast.Multiply
|
||||||
|
case token.Slash:
|
||||||
|
op = ast.Divide
|
||||||
|
default:
|
||||||
|
return p.exprError(p.curToken, "invalid token for binary expression %s", p.curToken.Type)
|
||||||
|
}
|
||||||
|
tok := p.curToken
|
||||||
|
|
||||||
|
precedence := p.curPrecedence()
|
||||||
|
p.nextToken()
|
||||||
|
rhs := p.parseExpression(precedence)
|
||||||
|
|
||||||
|
return &ast.BinaryExpression{Lhs: lhs, Rhs: rhs, Operator: op, Token: tok}
|
||||||
|
}
|
||||||
|
17
tast/tast.go
17
tast/tast.go
@ -8,6 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"robaertschi.xyz/robaertschi/tt/ast"
|
||||||
"robaertschi.xyz/robaertschi/tt/token"
|
"robaertschi.xyz/robaertschi/tt/token"
|
||||||
"robaertschi.xyz/robaertschi/tt/types"
|
"robaertschi.xyz/robaertschi/tt/types"
|
||||||
)
|
)
|
||||||
@ -74,3 +75,19 @@ func (ie *IntegerExpression) Type() types.Type {
|
|||||||
}
|
}
|
||||||
func (ie *IntegerExpression) TokenLiteral() string { return ie.Token.Literal }
|
func (ie *IntegerExpression) TokenLiteral() string { return ie.Token.Literal }
|
||||||
func (ie *IntegerExpression) String() string { return ie.Token.Literal }
|
func (ie *IntegerExpression) String() string { return ie.Token.Literal }
|
||||||
|
|
||||||
|
type BinaryExpression struct {
|
||||||
|
Token token.Token // The operator
|
||||||
|
Lhs, Rhs Expression
|
||||||
|
Operator ast.BinaryOperator
|
||||||
|
ResultType types.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func (be *BinaryExpression) expressionNode() {}
|
||||||
|
func (be *BinaryExpression) Type() types.Type {
|
||||||
|
return be.ResultType
|
||||||
|
}
|
||||||
|
func (be *BinaryExpression) TokenLiteral() string { return be.Token.Literal }
|
||||||
|
func (be *BinaryExpression) String() string {
|
||||||
|
return fmt.Sprintf("%s %s %s", be.Lhs, be.Operator, be.Rhs)
|
||||||
|
}
|
||||||
|
@ -26,13 +26,17 @@ const (
|
|||||||
Ident TokenType = "IDENT"
|
Ident TokenType = "IDENT"
|
||||||
Int TokenType = "INT"
|
Int TokenType = "INT"
|
||||||
|
|
||||||
Semicolon = ";"
|
Semicolon TokenType = ";"
|
||||||
Equal = "="
|
Equal TokenType = "="
|
||||||
OpenParen = "("
|
OpenParen TokenType = "("
|
||||||
CloseParen = ")"
|
CloseParen TokenType = ")"
|
||||||
|
Plus TokenType = "+"
|
||||||
|
Minus TokenType = "-"
|
||||||
|
Asterisk TokenType = "*"
|
||||||
|
Slash TokenType = "/"
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
Fn = "FN"
|
Fn TokenType = "FN"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LookupKeyword(literal string) TokenType {
|
func LookupKeyword(literal string) TokenType {
|
||||||
|
21
ttir/emit.go
21
ttir/emit.go
@ -1,6 +1,17 @@
|
|||||||
package ttir
|
package ttir
|
||||||
|
|
||||||
import "robaertschi.xyz/robaertschi/tt/tast"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"robaertschi.xyz/robaertschi/tt/tast"
|
||||||
|
)
|
||||||
|
|
||||||
|
var uniqueId int64
|
||||||
|
|
||||||
|
func temp() string {
|
||||||
|
uniqueId += 1
|
||||||
|
return fmt.Sprintf("temp.%d", uniqueId)
|
||||||
|
}
|
||||||
|
|
||||||
func EmitProgram(program *tast.Program) *Program {
|
func EmitProgram(program *tast.Program) *Program {
|
||||||
functions := make([]Function, 0)
|
functions := make([]Function, 0)
|
||||||
@ -29,6 +40,14 @@ func emitExpression(expr tast.Expression) (Operand, []Instruction) {
|
|||||||
switch expr := expr.(type) {
|
switch expr := expr.(type) {
|
||||||
case *tast.IntegerExpression:
|
case *tast.IntegerExpression:
|
||||||
return &Constant{Value: expr.Value}, []Instruction{}
|
return &Constant{Value: expr.Value}, []Instruction{}
|
||||||
|
case *tast.BinaryExpression:
|
||||||
|
lhsDst, instructions := emitExpression(expr.Lhs)
|
||||||
|
rhsDst, rhsInstructions := emitExpression(expr.Rhs)
|
||||||
|
instructions = append(instructions, rhsInstructions...)
|
||||||
|
dst := &Var{Value: temp()}
|
||||||
|
instructions = append(instructions, &Binary{Operator: expr.Operator, Lhs: lhsDst, Rhs: rhsDst, Dst: dst})
|
||||||
|
return dst, instructions
|
||||||
|
|
||||||
}
|
}
|
||||||
panic("unhandled tast.Expression case in ir emitter")
|
panic("unhandled tast.Expression case in ir emitter")
|
||||||
}
|
}
|
||||||
|
23
ttir/ttir.go
23
ttir/ttir.go
@ -3,6 +3,8 @@ package ttir
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"robaertschi.xyz/robaertschi/tt/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Program struct {
|
type Program struct {
|
||||||
@ -38,6 +40,18 @@ func (r *Ret) String() string {
|
|||||||
}
|
}
|
||||||
func (r *Ret) instruction() {}
|
func (r *Ret) instruction() {}
|
||||||
|
|
||||||
|
type Binary struct {
|
||||||
|
Operator ast.BinaryOperator
|
||||||
|
Lhs Operand
|
||||||
|
Rhs Operand
|
||||||
|
Dst Operand
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Binary) String() string {
|
||||||
|
return fmt.Sprintf("%s = %s %s, %s", b.Dst, b.Operator, b.Lhs, b.Rhs)
|
||||||
|
}
|
||||||
|
func (b *Binary) instruction() {}
|
||||||
|
|
||||||
type Operand interface {
|
type Operand interface {
|
||||||
String() string
|
String() string
|
||||||
operand()
|
operand()
|
||||||
@ -51,3 +65,12 @@ func (c *Constant) String() string {
|
|||||||
return fmt.Sprintf("%d", c.Value)
|
return fmt.Sprintf("%d", c.Value)
|
||||||
}
|
}
|
||||||
func (c *Constant) operand() {}
|
func (c *Constant) operand() {}
|
||||||
|
|
||||||
|
type Var struct {
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Var) String() string {
|
||||||
|
return v.Value
|
||||||
|
}
|
||||||
|
func (v *Var) operand() {}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"robaertschi.xyz/robaertschi/tt/ast"
|
"robaertschi.xyz/robaertschi/tt/ast"
|
||||||
"robaertschi.xyz/robaertschi/tt/tast"
|
"robaertschi.xyz/robaertschi/tt/tast"
|
||||||
"robaertschi.xyz/robaertschi/tt/token"
|
"robaertschi.xyz/robaertschi/tt/token"
|
||||||
|
"robaertschi.xyz/robaertschi/tt/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Checker struct {
|
type Checker struct {
|
||||||
@ -66,6 +67,20 @@ func (c *Checker) checkExpression(expr ast.Expression) (tast.Expression, error)
|
|||||||
return &tast.IntegerExpression{Token: expr.Token, Value: expr.Value}, nil
|
return &tast.IntegerExpression{Token: expr.Token, Value: expr.Value}, nil
|
||||||
case *ast.ErrorExpression:
|
case *ast.ErrorExpression:
|
||||||
return nil, c.error(expr.InvalidToken, "invalid expression")
|
return nil, c.error(expr.InvalidToken, "invalid expression")
|
||||||
|
case *ast.BinaryExpression:
|
||||||
|
lhs, lhsErr := c.checkExpression(expr.Lhs)
|
||||||
|
rhs, rhsErr := c.checkExpression(expr.Rhs)
|
||||||
|
var operandErr error
|
||||||
|
var resultType types.Type
|
||||||
|
if lhsErr == nil && rhsErr == nil {
|
||||||
|
if !lhs.Type().IsSameType(rhs.Type()) {
|
||||||
|
operandErr = fmt.Errorf("the lhs of the expression does not have the same type then the rhs, lhs=%q, rhs=%q", lhs.Type(), rhs.Type())
|
||||||
|
} else {
|
||||||
|
resultType = lhs.Type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tast.BinaryExpression{Lhs: lhs, Rhs: rhs, Operator: expr.Operator, Token: expr.Token, ResultType: resultType}, errors.Join(lhsErr, rhsErr, operandErr)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unhandled expression in type checker")
|
return nil, fmt.Errorf("unhandled expression in type checker")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user