diff options
author | Himbeer <himbeer@disroot.org> | 2024-09-01 12:16:24 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-09-01 12:16:24 +0200 |
commit | 661055b2ea93896bc4895f5659ea11a5ca07b06a (patch) | |
tree | f88c2809b84c35bbcfc4afef1ce13609333b8bea | |
parent | a7a15e1193b09414316fea40d6999f47bc0f57d4 (diff) |
Implement remainder operator and assignment statement
-rw-r--r-- | GRAMMAR.txt | 10 | ||||
-rw-r--r-- | expression.go | 14 | ||||
-rw-r--r-- | generate.go | 26 | ||||
-rw-r--r-- | lex.go | 12 | ||||
-rw-r--r-- | op.go | 1 | ||||
-rw-r--r-- | parse.go | 55 | ||||
-rw-r--r-- | token.go | 6 |
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) @@ -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 ')': @@ -39,6 +39,7 @@ type mulDivOp int const ( multiply mulDivOp = iota divide + remainder ) type unaryOp int @@ -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 @@ -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 |