aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-09-01 12:16:24 +0200
committerHimbeer <himbeer@disroot.org>2024-09-01 12:16:24 +0200
commit661055b2ea93896bc4895f5659ea11a5ca07b06a (patch)
treef88c2809b84c35bbcfc4afef1ce13609333b8bea
parenta7a15e1193b09414316fea40d6999f47bc0f57d4 (diff)
Implement remainder operator and assignment statement
-rw-r--r--GRAMMAR.txt10
-rw-r--r--expression.go14
-rw-r--r--generate.go26
-rw-r--r--lex.go12
-rw-r--r--op.go1
-rw-r--r--parse.go55
-rw-r--r--token.go6
7 files changed, 121 insertions, 3 deletions
diff --git a/GRAMMAR.txt b/GRAMMAR.txt
index a2011e6..47118ff 100644
--- a/GRAMMAR.txt
+++ b/GRAMMAR.txt
@@ -17,19 +17,25 @@ declaration -> constant | mutable
constant -> "const" IDENTIFIER "=" expression
mutable -> "mut" IDENTIFIER "=" expression
-assignment -> assign | addassign | subassign | mulassign | divassign
+assignment -> assign
+ | addassign
+ | subassign
+ | mulassign
+ | divassign
+ | remassign
assign -> IDENTIFIER "=" expression
addassign -> IDENTIFIER "+=" expression
subassign -> IDENTIFIER "-=" expression
mulassign -> IDENTIFIER "*=" expression
divassign -> IDENTIFIER "/=" expression
+remassign -> IDENTIFIER "%=" expression
expression -> equality
equality -> comparison ( ( "==" | "!=" ) comparison )*
comparison -> term ( ( "<" | "<=" | ">" | ">=" ) term )?
term -> numeral ( ( "<<" | ">>" ) numeral )*
numeral -> factor ( ( "+" | "-" ) factor )*
-factor -> unary ( ( "*" | "/" ) unary )*
+factor -> unary ( ( "*" | "/" | "%" ) unary )*
unary -> ( "-" | "!" | "~" )? primary
primary -> grouping | literal | call | variable
grouping -> "(" expression ")"
diff --git a/expression.go b/expression.go
index 27f4ddb..99bd4cb 100644
--- a/expression.go
+++ b/expression.go
@@ -209,6 +209,20 @@ func (d *divAssignStmt) markAssign() {}
func (d *divAssignStmt) line() int { return d.ln }
+type remAssignStmt struct {
+ name string
+ value exprExpr
+ ln int
+}
+
+func (r *remAssignStmt) markExpr() {}
+
+func (r *remAssignStmt) markStmt() {}
+
+func (r *remAssignStmt) markAssign() {}
+
+func (r *remAssignStmt) line() int { return r.ln }
+
type exprExpr interface {
expression
markExprExpr()
diff --git a/generate.go b/generate.go
index 51eb7c0..b8c6ba2 100644
--- a/generate.go
+++ b/generate.go
@@ -136,6 +136,8 @@ func generateStatement(stmt statementExpr, w io.Writer) error {
return generateMulAssignStmt(s, w)
case *divAssignStmt:
return generateDivAssignStmt(s, w)
+ case *remAssignStmt:
+ return generateRemAssignStmt(s, w)
}
return nil
@@ -291,6 +293,28 @@ func generateDivAssignStmt(stmt *divAssignStmt, w io.Writer) error {
return nil
}
+func generateRemAssignStmt(stmt *remAssignStmt, w io.Writer) error {
+ ok, mutable := isDeclared(stmt.name, false)
+ if !ok {
+ return errUndeclared{name: stmt.name, line: stmt.line()}
+ }
+ if !mutable {
+ return errImmutable{name: stmt.name, line: stmt.line()}
+ }
+
+ value, err := stmt.value.generate(w)
+ if err != nil {
+ return err
+ }
+
+ in, out := allocReg(), allocReg()
+
+ fmt.Fprintf(w, "%s =w loadl %%%s\n", in, stmt.name)
+ fmt.Fprintf(w, "%s =w rem %s, %s\n", out, in, value)
+ fmt.Fprintf(w, "storew %s, %%%s\n", out, stmt.name)
+ return nil
+}
+
func (e *equalityExpr) generate(w io.Writer) (string, error) {
lhs, err := e.lhs.generate(w)
if err != nil {
@@ -476,6 +500,8 @@ func (f *factorRhs) generate(in string, w io.Writer) (string, error) {
instruction += "mul"
case divide:
instruction += "div"
+ case remainder:
+ instruction += "rem"
}
rhs, err := f.value.generate(w)
diff --git a/lex.go b/lex.go
index 7450888..f0631da 100644
--- a/lex.go
+++ b/lex.go
@@ -111,6 +111,18 @@ func readToken(br *bufio.Reader, line *int) (token, error) {
br.UnreadRune()
return token{kind: slash, line: *line}, nil
}
+ case '%':
+ next, _, err := br.ReadRune()
+ if err != nil {
+ return token{}, err
+ }
+
+ if next == '=' {
+ return token{kind: percentageEquals, line: *line}, nil
+ } else {
+ br.UnreadRune()
+ return token{kind: percentage, line: *line}, nil
+ }
case '(':
return token{kind: lparen, line: *line}, nil
case ')':
diff --git a/op.go b/op.go
index 70977a1..8f67ae8 100644
--- a/op.go
+++ b/op.go
@@ -39,6 +39,7 @@ type mulDivOp int
const (
multiply mulDivOp = iota
divide
+ remainder
)
type unaryOp int
diff --git a/parse.go b/parse.go
index f15ac0a..321c679 100644
--- a/parse.go
+++ b/parse.go
@@ -382,6 +382,14 @@ func parseAssignment(toks *tokens) (assignmentStmt, error) {
return divAssign, nil
}
+ remAssign, err := parseRemAssignStmt(toks)
+ if err != nil {
+ return nil, err
+ }
+ if remAssign != nil {
+ return remAssign, nil
+ }
+
return nil, nil
}
@@ -598,6 +606,37 @@ func parseDivAssignStmt(toks *tokens) (*divAssignStmt, error) {
}, nil
}
+func parseRemAssignStmt(toks *tokens) (*remAssignStmt, error) {
+ nameTok, ok := toks.consumeToken()
+ if !ok {
+ return nil, unexpectedEOF
+ }
+ if nameTok.kind != identifier {
+ toks.unreadToken()
+ return nil, nil
+ }
+
+ ok, err := toks.match(percentageEquals)
+ if err != nil {
+ return nil, err
+ }
+ if !ok {
+ toks.unreadTokens(2)
+ return nil, nil
+ }
+
+ expr, err := parseExpression(toks)
+ if err != nil {
+ return nil, err
+ }
+
+ return &remAssignStmt{
+ name: nameTok.value,
+ value: expr,
+ ln: nameTok.line,
+ }, nil
+}
+
func parseExpression(toks *tokens) (exprExpr, error) {
return parseEquality(toks)
}
@@ -880,7 +919,19 @@ func parseFactorRhs(toks *tokens) (*factorRhs, error) {
if err != nil {
return nil, err
}
- if !div {
+ }
+ var rem bool
+ if !mul && !div {
+ toks.unreadToken()
+ if mul {
+ toks.unreadToken()
+ }
+
+ rem, err = toks.match(percentage)
+ if err != nil {
+ return nil, err
+ }
+ if !rem {
toks.unreadToken()
return nil, nil
}
@@ -896,6 +947,8 @@ func parseFactorRhs(toks *tokens) (*factorRhs, error) {
op = multiply
} else if div {
op = divide
+ } else if rem {
+ op = remainder
}
return &factorRhs{op: op, value: value}, nil
diff --git a/token.go b/token.go
index 20d4727..42c8041 100644
--- a/token.go
+++ b/token.go
@@ -24,6 +24,10 @@ func (k tokenKind) String() string {
return "/="
case slash:
return "/"
+ case percentageEquals:
+ return "%="
+ case percentage:
+ return "%"
case lparen:
return "("
case rparen:
@@ -119,6 +123,8 @@ const (
star
slashEquals
slash
+ percentageEquals
+ percentage
lparen
rparen
lbracket