started work on c compiler
This commit is contained in:
Generated
+4
@@ -539,6 +539,10 @@ version = "1.10.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "c_compiler"
|
||||||
|
version = "0.2.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "calloop"
|
name = "calloop"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
cargo-features = ["codegen-backend"]
|
cargo-features = ["codegen-backend"]
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["emulator", "common", "assembler", "dsa_editor", "compiler"]
|
members = ["emulator", "common", "assembler", "dsa_editor", "compiler", "c_compiler"]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
|
|||||||
@@ -138,6 +138,11 @@ fn assemble(src: &Path) -> Result<Vec<Instruction>, AssembleError> {
|
|||||||
create_sections(&mut nodes)?;
|
create_sections(&mut nodes)?;
|
||||||
resolve_symbols(&mut nodes)?;
|
resolve_symbols(&mut nodes)?;
|
||||||
|
|
||||||
|
println!("Generating assembly output...");
|
||||||
|
for n in &nodes {
|
||||||
|
println!("{n}");
|
||||||
|
}
|
||||||
|
|
||||||
let instructions = codegen(nodes)?;
|
let instructions = codegen(nodes)?;
|
||||||
Ok(instructions)
|
Ok(instructions)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "c_compiler"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
int factorial(int n) {
|
||||||
|
if (n <= 1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return n * factorial(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int add(int a, int b) { return a + b; }
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int x;
|
||||||
|
x = 5;
|
||||||
|
int x = 5;
|
||||||
|
int result;
|
||||||
|
int result = 5;
|
||||||
|
result = x + factorial(5);
|
||||||
|
print(result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,926 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Simple C to DSA Assembly Compiler
|
||||||
|
Supports a subset of C including:
|
||||||
|
- int variables and functions
|
||||||
|
- Arithmetic operations (+, -, *, /)
|
||||||
|
- Comparisons (==, !=, <, >, <=, >=)
|
||||||
|
- If/else statements
|
||||||
|
- While loops
|
||||||
|
- Function calls
|
||||||
|
- Return statements
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from typing import List, Dict, Optional, Tuple
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from pprint import pprint
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class TokenType(Enum):
|
||||||
|
# Keywords
|
||||||
|
INT = "int"
|
||||||
|
IF = "if"
|
||||||
|
ELSE = "else"
|
||||||
|
WHILE = "while"
|
||||||
|
RETURN = "return"
|
||||||
|
|
||||||
|
# Identifiers and literals
|
||||||
|
IDENTIFIER = "IDENTIFIER"
|
||||||
|
NUMBER = "NUMBER"
|
||||||
|
|
||||||
|
# Operators
|
||||||
|
PLUS = "+"
|
||||||
|
MINUS = "-"
|
||||||
|
STAR = "*"
|
||||||
|
SLASH = "/"
|
||||||
|
ASSIGN = "="
|
||||||
|
EQ = "=="
|
||||||
|
NE = "!="
|
||||||
|
LT = "<"
|
||||||
|
GT = ">"
|
||||||
|
LE = "<="
|
||||||
|
GE = ">="
|
||||||
|
|
||||||
|
# Delimiters
|
||||||
|
LPAREN = "("
|
||||||
|
RPAREN = ")"
|
||||||
|
LBRACE = "{"
|
||||||
|
RBRACE = "}"
|
||||||
|
SEMICOLON = ";"
|
||||||
|
COMMA = ","
|
||||||
|
|
||||||
|
EOF = "EOF"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Token:
|
||||||
|
type: TokenType
|
||||||
|
value: str
|
||||||
|
line: int
|
||||||
|
col: int
|
||||||
|
|
||||||
|
|
||||||
|
class Lexer:
|
||||||
|
def __init__(self, source: str):
|
||||||
|
self.source = source
|
||||||
|
self.pos = 0
|
||||||
|
self.line = 1
|
||||||
|
self.col = 1
|
||||||
|
self.tokens = []
|
||||||
|
|
||||||
|
def error(self, msg: str):
|
||||||
|
raise SyntaxError(f"Lexer error at line {self.line}, col {self.col}: {msg}")
|
||||||
|
|
||||||
|
def peek(self, offset: int = 0) -> Optional[str]:
|
||||||
|
pos = self.pos + offset
|
||||||
|
return self.source[pos] if pos < len(self.source) else None
|
||||||
|
|
||||||
|
def advance(self) -> Optional[str]:
|
||||||
|
if self.pos >= len(self.source):
|
||||||
|
return None
|
||||||
|
char = self.source[self.pos]
|
||||||
|
self.pos += 1
|
||||||
|
if char == "\n":
|
||||||
|
self.line += 1
|
||||||
|
self.col = 1
|
||||||
|
else:
|
||||||
|
self.col += 1
|
||||||
|
return char
|
||||||
|
|
||||||
|
def skip_whitespace(self):
|
||||||
|
while self.peek() and self.peek() in " \t\n\r":
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
def skip_comment(self):
|
||||||
|
if self.peek() == "/" and self.peek(1) == "/":
|
||||||
|
while self.peek() and self.peek() != "\n":
|
||||||
|
self.advance()
|
||||||
|
self.advance() # skip newline
|
||||||
|
|
||||||
|
def read_number(self) -> str:
|
||||||
|
num = ""
|
||||||
|
while self.peek() and self.peek().isdigit():
|
||||||
|
num += self.advance()
|
||||||
|
return num
|
||||||
|
|
||||||
|
def read_identifier(self) -> str:
|
||||||
|
ident = ""
|
||||||
|
while self.peek() and (self.peek().isalnum() or self.peek() == "_"):
|
||||||
|
ident += self.advance()
|
||||||
|
return ident
|
||||||
|
|
||||||
|
def tokenize(self) -> List[Token]:
|
||||||
|
keywords = {
|
||||||
|
"int": TokenType.INT,
|
||||||
|
"if": TokenType.IF,
|
||||||
|
"else": TokenType.ELSE,
|
||||||
|
"while": TokenType.WHILE,
|
||||||
|
"return": TokenType.RETURN,
|
||||||
|
}
|
||||||
|
|
||||||
|
while self.pos < len(self.source):
|
||||||
|
self.skip_whitespace()
|
||||||
|
self.skip_comment()
|
||||||
|
|
||||||
|
if self.pos >= len(self.source):
|
||||||
|
break
|
||||||
|
|
||||||
|
line, col = self.line, self.col
|
||||||
|
char = self.peek()
|
||||||
|
|
||||||
|
# Numbers
|
||||||
|
if char.isdigit():
|
||||||
|
num = self.read_number()
|
||||||
|
self.tokens.append(Token(TokenType.NUMBER, num, line, col))
|
||||||
|
|
||||||
|
# Identifiers and keywords
|
||||||
|
elif char.isalpha() or char == "_":
|
||||||
|
ident = self.read_identifier()
|
||||||
|
token_type = keywords.get(ident, TokenType.IDENTIFIER)
|
||||||
|
self.tokens.append(Token(token_type, ident, line, col))
|
||||||
|
|
||||||
|
# Two-character operators
|
||||||
|
elif char == "=" and self.peek(1) == "=":
|
||||||
|
self.advance()
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.EQ, "==", line, col))
|
||||||
|
elif char == "!" and self.peek(1) == "=":
|
||||||
|
self.advance()
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.NE, "!=", line, col))
|
||||||
|
elif char == "<" and self.peek(1) == "=":
|
||||||
|
self.advance()
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.LE, "<=", line, col))
|
||||||
|
elif char == ">" and self.peek(1) == "=":
|
||||||
|
self.advance()
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.GE, ">=", line, col))
|
||||||
|
|
||||||
|
# Single-character operators
|
||||||
|
elif char == "+":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.PLUS, "+", line, col))
|
||||||
|
elif char == "-":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.MINUS, "-", line, col))
|
||||||
|
elif char == "*":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.STAR, "*", line, col))
|
||||||
|
elif char == "/":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.SLASH, "/", line, col))
|
||||||
|
elif char == "=":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.ASSIGN, "=", line, col))
|
||||||
|
elif char == "<":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.LT, "<", line, col))
|
||||||
|
elif char == ">":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.GT, ">", line, col))
|
||||||
|
elif char == "(":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.LPAREN, "(", line, col))
|
||||||
|
elif char == ")":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.RPAREN, ")", line, col))
|
||||||
|
elif char == "{":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.LBRACE, "{", line, col))
|
||||||
|
elif char == "}":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.RBRACE, "}", line, col))
|
||||||
|
elif char == ";":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.SEMICOLON, ";", line, col))
|
||||||
|
elif char == ",":
|
||||||
|
self.advance()
|
||||||
|
self.tokens.append(Token(TokenType.COMMA, ",", line, col))
|
||||||
|
else:
|
||||||
|
self.error(f"Unexpected character: {char}")
|
||||||
|
|
||||||
|
self.tokens.append(Token(TokenType.EOF, "", self.line, self.col))
|
||||||
|
return self.tokens
|
||||||
|
|
||||||
|
|
||||||
|
# AST Node classes
|
||||||
|
@dataclass
|
||||||
|
class ASTNode:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Program(ASTNode):
|
||||||
|
declarations: List["Declaration"]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Declaration(ASTNode):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FunctionDecl(Declaration):
|
||||||
|
name: str
|
||||||
|
params: List[str]
|
||||||
|
body: "CompoundStmt"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VarDecl(Declaration):
|
||||||
|
name: str
|
||||||
|
init: Optional["Expression"] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Statement(ASTNode):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CompoundStmt(Statement):
|
||||||
|
statements: List[Statement]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ExprStmt(Statement):
|
||||||
|
expr: Optional["Expression"]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class IfStmt(Statement):
|
||||||
|
condition: "Expression"
|
||||||
|
then_stmt: Statement
|
||||||
|
else_stmt: Optional[Statement] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WhileStmt(Statement):
|
||||||
|
condition: "Expression"
|
||||||
|
body: Statement
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ReturnStmt(Statement):
|
||||||
|
expr: Optional["Expression"]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Expression(ASTNode):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BinaryOp(Expression):
|
||||||
|
op: str
|
||||||
|
left: Expression
|
||||||
|
right: Expression
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class UnaryOp(Expression):
|
||||||
|
op: str
|
||||||
|
operand: Expression
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AssignExpr(Expression):
|
||||||
|
name: str
|
||||||
|
value: Expression
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VarExpr(Expression):
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NumberExpr(Expression):
|
||||||
|
value: int
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CallExpr(Expression):
|
||||||
|
name: str
|
||||||
|
args: List[Expression]
|
||||||
|
|
||||||
|
|
||||||
|
class Parser:
|
||||||
|
def __init__(self, tokens: List[Token]):
|
||||||
|
self.tokens = tokens
|
||||||
|
self.pos = 0
|
||||||
|
|
||||||
|
def error(self, msg: str):
|
||||||
|
token = self.current()
|
||||||
|
raise SyntaxError(f"Parser error at line {token.line}, col {token.col}: {msg}")
|
||||||
|
|
||||||
|
def current(self) -> Token:
|
||||||
|
return self.tokens[self.pos] if self.pos < len(self.tokens) else self.tokens[-1]
|
||||||
|
|
||||||
|
def peek(self, offset: int = 0) -> Token:
|
||||||
|
pos = self.pos + offset
|
||||||
|
return self.tokens[pos] if pos < len(self.tokens) else self.tokens[-1]
|
||||||
|
|
||||||
|
def advance(self) -> Token:
|
||||||
|
token = self.current()
|
||||||
|
if self.pos < len(self.tokens) - 1:
|
||||||
|
self.pos += 1
|
||||||
|
return token
|
||||||
|
|
||||||
|
def expect(self, token_type: TokenType) -> Token:
|
||||||
|
token = self.current()
|
||||||
|
if token.type != token_type:
|
||||||
|
self.error(f"Expected {token_type.value}, got {token.type.value}")
|
||||||
|
return self.advance()
|
||||||
|
|
||||||
|
def parse(self) -> Program:
|
||||||
|
declarations = []
|
||||||
|
while self.current().type != TokenType.EOF:
|
||||||
|
declarations.append(self.parse_declaration())
|
||||||
|
return Program(declarations)
|
||||||
|
|
||||||
|
def parse_declaration(self) -> Declaration:
|
||||||
|
self.expect(TokenType.INT)
|
||||||
|
name = self.expect(TokenType.IDENTIFIER).value
|
||||||
|
|
||||||
|
if self.current().type == TokenType.LPAREN:
|
||||||
|
# Function declaration
|
||||||
|
self.advance()
|
||||||
|
params = []
|
||||||
|
|
||||||
|
if self.current().type != TokenType.RPAREN:
|
||||||
|
self.expect(TokenType.INT)
|
||||||
|
params.append(self.expect(TokenType.IDENTIFIER).value)
|
||||||
|
|
||||||
|
while self.current().type == TokenType.COMMA:
|
||||||
|
self.advance()
|
||||||
|
self.expect(TokenType.INT)
|
||||||
|
params.append(self.expect(TokenType.IDENTIFIER).value)
|
||||||
|
|
||||||
|
self.expect(TokenType.RPAREN)
|
||||||
|
body = self.parse_compound_stmt()
|
||||||
|
return FunctionDecl(name, params, body)
|
||||||
|
else:
|
||||||
|
# Variable declaration
|
||||||
|
init = None
|
||||||
|
if self.current().type == TokenType.ASSIGN:
|
||||||
|
self.advance()
|
||||||
|
init = self.parse_expression()
|
||||||
|
self.expect(TokenType.SEMICOLON)
|
||||||
|
return VarDecl(name, init)
|
||||||
|
|
||||||
|
def parse_compound_stmt(self) -> CompoundStmt:
|
||||||
|
self.expect(TokenType.LBRACE)
|
||||||
|
statements = []
|
||||||
|
|
||||||
|
while self.current().type != TokenType.RBRACE:
|
||||||
|
statements.append(self.parse_statement())
|
||||||
|
|
||||||
|
self.expect(TokenType.RBRACE)
|
||||||
|
return CompoundStmt(statements)
|
||||||
|
|
||||||
|
def parse_statement(self) -> Statement:
|
||||||
|
token = self.current()
|
||||||
|
|
||||||
|
if token.type == TokenType.LBRACE:
|
||||||
|
return self.parse_compound_stmt()
|
||||||
|
elif token.type == TokenType.IF:
|
||||||
|
return self.parse_if_stmt()
|
||||||
|
elif token.type == TokenType.WHILE:
|
||||||
|
return self.parse_while_stmt()
|
||||||
|
elif token.type == TokenType.RETURN:
|
||||||
|
return self.parse_return_stmt()
|
||||||
|
elif token.type == TokenType.INT:
|
||||||
|
# Local variable declaration
|
||||||
|
self.advance()
|
||||||
|
name = self.expect(TokenType.IDENTIFIER).value
|
||||||
|
init = None
|
||||||
|
if self.current().type == TokenType.ASSIGN:
|
||||||
|
self.advance()
|
||||||
|
init = self.parse_expression()
|
||||||
|
self.expect(TokenType.SEMICOLON)
|
||||||
|
return ExprStmt(AssignExpr(name, init) if init else None)
|
||||||
|
else:
|
||||||
|
expr = (
|
||||||
|
self.parse_expression()
|
||||||
|
if self.current().type != TokenType.SEMICOLON
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
self.expect(TokenType.SEMICOLON)
|
||||||
|
return ExprStmt(expr)
|
||||||
|
|
||||||
|
def parse_if_stmt(self) -> IfStmt:
|
||||||
|
self.expect(TokenType.IF)
|
||||||
|
self.expect(TokenType.LPAREN)
|
||||||
|
condition = self.parse_expression()
|
||||||
|
self.expect(TokenType.RPAREN)
|
||||||
|
then_stmt = self.parse_statement()
|
||||||
|
|
||||||
|
else_stmt = None
|
||||||
|
if self.current().type == TokenType.ELSE:
|
||||||
|
self.advance()
|
||||||
|
else_stmt = self.parse_statement()
|
||||||
|
|
||||||
|
return IfStmt(condition, then_stmt, else_stmt)
|
||||||
|
|
||||||
|
def parse_while_stmt(self) -> WhileStmt:
|
||||||
|
self.expect(TokenType.WHILE)
|
||||||
|
self.expect(TokenType.LPAREN)
|
||||||
|
condition = self.parse_expression()
|
||||||
|
self.expect(TokenType.RPAREN)
|
||||||
|
body = self.parse_statement()
|
||||||
|
return WhileStmt(condition, body)
|
||||||
|
|
||||||
|
def parse_return_stmt(self) -> ReturnStmt:
|
||||||
|
self.expect(TokenType.RETURN)
|
||||||
|
expr = None
|
||||||
|
if self.current().type != TokenType.SEMICOLON:
|
||||||
|
expr = self.parse_expression()
|
||||||
|
self.expect(TokenType.SEMICOLON)
|
||||||
|
return ReturnStmt(expr)
|
||||||
|
|
||||||
|
def parse_expression(self) -> Expression:
|
||||||
|
return self.parse_assignment()
|
||||||
|
|
||||||
|
def parse_assignment(self) -> Expression:
|
||||||
|
expr = self.parse_comparison()
|
||||||
|
|
||||||
|
if self.current().type == TokenType.ASSIGN:
|
||||||
|
if not isinstance(expr, VarExpr):
|
||||||
|
self.error("Invalid assignment target")
|
||||||
|
self.advance()
|
||||||
|
value = self.parse_assignment()
|
||||||
|
return AssignExpr(expr.name, value)
|
||||||
|
|
||||||
|
return expr
|
||||||
|
|
||||||
|
def parse_comparison(self) -> Expression:
|
||||||
|
expr = self.parse_additive()
|
||||||
|
|
||||||
|
while self.current().type in [
|
||||||
|
TokenType.EQ,
|
||||||
|
TokenType.NE,
|
||||||
|
TokenType.LT,
|
||||||
|
TokenType.GT,
|
||||||
|
TokenType.LE,
|
||||||
|
TokenType.GE,
|
||||||
|
]:
|
||||||
|
op = self.advance().value
|
||||||
|
right = self.parse_additive()
|
||||||
|
expr = BinaryOp(op, expr, right)
|
||||||
|
|
||||||
|
return expr
|
||||||
|
|
||||||
|
def parse_additive(self) -> Expression:
|
||||||
|
expr = self.parse_multiplicative()
|
||||||
|
|
||||||
|
while self.current().type in [TokenType.PLUS, TokenType.MINUS]:
|
||||||
|
op = self.advance().value
|
||||||
|
right = self.parse_multiplicative()
|
||||||
|
expr = BinaryOp(op, expr, right)
|
||||||
|
|
||||||
|
return expr
|
||||||
|
|
||||||
|
def parse_multiplicative(self) -> Expression:
|
||||||
|
expr = self.parse_unary()
|
||||||
|
|
||||||
|
while self.current().type in [TokenType.STAR, TokenType.SLASH]:
|
||||||
|
op = self.advance().value
|
||||||
|
right = self.parse_unary()
|
||||||
|
expr = BinaryOp(op, expr, right)
|
||||||
|
|
||||||
|
return expr
|
||||||
|
|
||||||
|
def parse_unary(self) -> Expression:
|
||||||
|
if self.current().type in [TokenType.PLUS, TokenType.MINUS]:
|
||||||
|
op = self.advance().value
|
||||||
|
operand = self.parse_unary()
|
||||||
|
return UnaryOp(op, operand)
|
||||||
|
|
||||||
|
return self.parse_primary()
|
||||||
|
|
||||||
|
def parse_primary(self) -> Expression:
|
||||||
|
token = self.current()
|
||||||
|
|
||||||
|
if token.type == TokenType.NUMBER:
|
||||||
|
self.advance()
|
||||||
|
return NumberExpr(int(token.value))
|
||||||
|
|
||||||
|
elif token.type == TokenType.IDENTIFIER:
|
||||||
|
name = self.advance().value
|
||||||
|
|
||||||
|
if self.current().type == TokenType.LPAREN:
|
||||||
|
# Function call
|
||||||
|
self.advance()
|
||||||
|
args = []
|
||||||
|
|
||||||
|
if self.current().type != TokenType.RPAREN:
|
||||||
|
args.append(self.parse_expression())
|
||||||
|
while self.current().type == TokenType.COMMA:
|
||||||
|
self.advance()
|
||||||
|
args.append(self.parse_expression())
|
||||||
|
|
||||||
|
self.expect(TokenType.RPAREN)
|
||||||
|
return CallExpr(name, args)
|
||||||
|
else:
|
||||||
|
return VarExpr(name)
|
||||||
|
|
||||||
|
elif token.type == TokenType.LPAREN:
|
||||||
|
self.advance()
|
||||||
|
expr = self.parse_expression()
|
||||||
|
self.expect(TokenType.RPAREN)
|
||||||
|
return expr
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.error(f"Unexpected token: {token.type.value}")
|
||||||
|
|
||||||
|
|
||||||
|
class CodeGenerator:
|
||||||
|
def __init__(self):
|
||||||
|
self.output = []
|
||||||
|
self.label_counter = 0
|
||||||
|
self.string_counter = 0
|
||||||
|
self.functions = {}
|
||||||
|
self.current_function = None
|
||||||
|
self.local_vars = {}
|
||||||
|
self.global_vars = {}
|
||||||
|
self.register_pool = [f"rg{i:x}" for i in range(16)]
|
||||||
|
self.used_registers = set()
|
||||||
|
|
||||||
|
def new_label(self, prefix: str = "L") -> str:
|
||||||
|
label = f"{prefix}{self.label_counter}"
|
||||||
|
self.label_counter += 1
|
||||||
|
return label
|
||||||
|
|
||||||
|
def allocate_register(self) -> str:
|
||||||
|
for reg in self.register_pool:
|
||||||
|
if reg not in self.used_registers:
|
||||||
|
self.used_registers.add(reg)
|
||||||
|
return reg
|
||||||
|
raise RuntimeError("Out of registers")
|
||||||
|
|
||||||
|
def free_register(self, reg: str):
|
||||||
|
self.used_registers.discard(reg)
|
||||||
|
|
||||||
|
def emit(self, code: str):
|
||||||
|
self.output.append(code)
|
||||||
|
|
||||||
|
def generate(self, program: Program) -> str:
|
||||||
|
# Emit data section
|
||||||
|
self.emit("// Global variables")
|
||||||
|
for decl in program.declarations:
|
||||||
|
if isinstance(decl, VarDecl):
|
||||||
|
self.global_vars[decl.name] = f"var_{decl.name}"
|
||||||
|
if decl.init:
|
||||||
|
if isinstance(decl.init, NumberExpr):
|
||||||
|
self.emit(f"dw var_{decl.name}: {decl.init.value}")
|
||||||
|
else:
|
||||||
|
self.emit(f"dw var_{decl.name}: 0")
|
||||||
|
else:
|
||||||
|
self.emit(f"dw var_{decl.name}: 0")
|
||||||
|
|
||||||
|
self.emit("")
|
||||||
|
self.emit("// Entry point")
|
||||||
|
self.emit("dw stack_bottom: 0x10000")
|
||||||
|
self.emit("")
|
||||||
|
self.emit("init:")
|
||||||
|
self.emit(" ldw stack_bottom, spr")
|
||||||
|
self.emit(" mov spr, bpr")
|
||||||
|
|
||||||
|
self.emit(" push zero")
|
||||||
|
self.emit(" call main")
|
||||||
|
self.emit(" pop rg0")
|
||||||
|
self.emit(" hlt")
|
||||||
|
self.emit("")
|
||||||
|
|
||||||
|
# Emit functions
|
||||||
|
for decl in program.declarations:
|
||||||
|
if isinstance(decl, FunctionDecl):
|
||||||
|
self.generate_function(decl)
|
||||||
|
|
||||||
|
return "\n".join(self.output)
|
||||||
|
|
||||||
|
def generate_function(self, func: FunctionDecl):
|
||||||
|
self.current_function = func.name
|
||||||
|
self.functions[func.name] = func
|
||||||
|
self.local_vars = {}
|
||||||
|
|
||||||
|
# Map parameters to stack offsets
|
||||||
|
# Parameters start at bpr+8 (after return addr at bpr+4)
|
||||||
|
for i, param in enumerate(func.params):
|
||||||
|
self.local_vars[param] = 8 + (i * 4)
|
||||||
|
|
||||||
|
self.emit(f"{func.name}:")
|
||||||
|
self.emit(" push bpr")
|
||||||
|
self.emit(" mov spr, bpr")
|
||||||
|
self.emit("")
|
||||||
|
|
||||||
|
# Generate function body
|
||||||
|
self.generate_compound_stmt(func.body)
|
||||||
|
|
||||||
|
# Default return if no explicit return
|
||||||
|
self.emit("// default return")
|
||||||
|
self.emit(f"{func.name}_end:")
|
||||||
|
self.emit(" mov bpr, spr")
|
||||||
|
self.emit(" pop bpr")
|
||||||
|
self.emit(" return")
|
||||||
|
self.emit("")
|
||||||
|
|
||||||
|
def generate_compound_stmt(self, stmt: CompoundStmt):
|
||||||
|
for s in stmt.statements:
|
||||||
|
self.generate_statement(s)
|
||||||
|
|
||||||
|
def generate_statement(self, stmt: Statement):
|
||||||
|
if isinstance(stmt, CompoundStmt):
|
||||||
|
self.generate_compound_stmt(stmt)
|
||||||
|
elif isinstance(stmt, ExprStmt):
|
||||||
|
if stmt.expr:
|
||||||
|
reg = self.generate_expression(stmt.expr)
|
||||||
|
self.free_register(reg)
|
||||||
|
elif isinstance(stmt, IfStmt):
|
||||||
|
self.generate_if_stmt(stmt)
|
||||||
|
elif isinstance(stmt, WhileStmt):
|
||||||
|
self.generate_while_stmt(stmt)
|
||||||
|
elif isinstance(stmt, ReturnStmt):
|
||||||
|
self.generate_return_stmt(stmt)
|
||||||
|
|
||||||
|
def generate_if_stmt(self, stmt: IfStmt):
|
||||||
|
else_label = self.new_label("else")
|
||||||
|
end_label = self.new_label("endif")
|
||||||
|
|
||||||
|
# Evaluate condition
|
||||||
|
cond_reg = self.generate_expression(stmt.condition)
|
||||||
|
self.emit(f" cmp {cond_reg}, zero")
|
||||||
|
self.free_register(cond_reg)
|
||||||
|
|
||||||
|
if stmt.else_stmt:
|
||||||
|
self.emit(f" jeq {else_label}")
|
||||||
|
else:
|
||||||
|
self.emit(f" jeq {end_label}")
|
||||||
|
|
||||||
|
# Then branch
|
||||||
|
self.generate_statement(stmt.then_stmt)
|
||||||
|
|
||||||
|
if stmt.else_stmt:
|
||||||
|
self.emit(f" jmp {end_label}")
|
||||||
|
self.emit(f"{else_label}:")
|
||||||
|
self.generate_statement(stmt.else_stmt)
|
||||||
|
|
||||||
|
self.emit(f"{end_label}:")
|
||||||
|
|
||||||
|
def generate_while_stmt(self, stmt: WhileStmt):
|
||||||
|
start_label = self.new_label("while_start")
|
||||||
|
end_label = self.new_label("while_end")
|
||||||
|
|
||||||
|
self.emit(f"{start_label}:")
|
||||||
|
|
||||||
|
# Evaluate condition
|
||||||
|
cond_reg = self.generate_expression(stmt.condition)
|
||||||
|
self.emit(f" cmp {cond_reg}, zero")
|
||||||
|
self.free_register(cond_reg)
|
||||||
|
self.emit(f" jeq {end_label}")
|
||||||
|
|
||||||
|
# Loop body
|
||||||
|
self.generate_statement(stmt.body)
|
||||||
|
self.emit(f" jmp {start_label}")
|
||||||
|
|
||||||
|
self.emit(f"{end_label}:")
|
||||||
|
|
||||||
|
def generate_return_stmt(self, stmt: ReturnStmt):
|
||||||
|
if stmt.expr:
|
||||||
|
reg = self.generate_expression(stmt.expr)
|
||||||
|
# Store return value at spr+8 according to calling convention
|
||||||
|
self.emit(f" stw {reg}, spr, 8")
|
||||||
|
self.free_register(reg)
|
||||||
|
self.emit(f" jmp {self.current_function}_end")
|
||||||
|
|
||||||
|
def generate_expression(self, expr: Expression) -> str:
|
||||||
|
if isinstance(expr, NumberExpr):
|
||||||
|
reg = self.allocate_register()
|
||||||
|
if expr.value <= 0xFFFF and expr.value >= 0:
|
||||||
|
self.emit(f" lli {expr.value}, {reg}")
|
||||||
|
if expr.value > 0xFF:
|
||||||
|
self.emit(f" lui {expr.value >> 16}, {reg}")
|
||||||
|
else:
|
||||||
|
self.emit(f" lli {expr.value & 0xFFFF}, {reg}")
|
||||||
|
self.emit(f" lui {(expr.value >> 16) & 0xFFFF}, {reg}")
|
||||||
|
return reg
|
||||||
|
|
||||||
|
elif isinstance(expr, VarExpr):
|
||||||
|
reg = self.allocate_register()
|
||||||
|
if expr.name in self.local_vars:
|
||||||
|
offset = self.local_vars[expr.name]
|
||||||
|
self.emit(f" ldw bpr, {reg}, {offset}")
|
||||||
|
elif expr.name in self.global_vars:
|
||||||
|
label = self.global_vars[expr.name]
|
||||||
|
self.emit(f" ldw {label}, {reg}")
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Undefined variable: {expr.name}")
|
||||||
|
return reg
|
||||||
|
|
||||||
|
elif isinstance(expr, AssignExpr):
|
||||||
|
value_reg = self.generate_expression(expr.value)
|
||||||
|
|
||||||
|
if expr.name in self.local_vars:
|
||||||
|
offset = self.local_vars[expr.name]
|
||||||
|
self.emit(f" stw {value_reg}, bpr, {offset}")
|
||||||
|
elif expr.name in self.global_vars:
|
||||||
|
label = self.global_vars[expr.name]
|
||||||
|
self.emit(f" stw {value_reg}, {label}")
|
||||||
|
else:
|
||||||
|
# New local variable - allocate after params and return value space
|
||||||
|
# Start local variables at offset -4 from bpr (growing downward)
|
||||||
|
offset = -(len([v for v in self.local_vars.values() if v < 0]) + 1) * 4
|
||||||
|
self.local_vars[expr.name] = offset
|
||||||
|
self.emit(f" stw {value_reg}, bpr, {offset}")
|
||||||
|
|
||||||
|
return value_reg
|
||||||
|
|
||||||
|
elif isinstance(expr, BinaryOp):
|
||||||
|
return self.generate_binary_op(expr)
|
||||||
|
|
||||||
|
elif isinstance(expr, UnaryOp):
|
||||||
|
operand_reg = self.generate_expression(expr.operand)
|
||||||
|
result_reg = self.allocate_register()
|
||||||
|
|
||||||
|
if expr.op == "-":
|
||||||
|
self.emit(f" lwi 0, {result_reg}")
|
||||||
|
self.emit(f" sub {result_reg}, {operand_reg}, {result_reg}")
|
||||||
|
else: # +
|
||||||
|
self.emit(f" mov {operand_reg}, {result_reg}")
|
||||||
|
|
||||||
|
self.free_register(operand_reg)
|
||||||
|
return result_reg
|
||||||
|
|
||||||
|
elif isinstance(expr, CallExpr):
|
||||||
|
# First, make space for return value (must be pushed BEFORE arguments)
|
||||||
|
temp_reg = self.allocate_register()
|
||||||
|
|
||||||
|
# Then push arguments in reverse order
|
||||||
|
arg_regs = []
|
||||||
|
for arg in reversed(expr.args):
|
||||||
|
reg = self.generate_expression(arg)
|
||||||
|
self.emit(f" push {reg}")
|
||||||
|
arg_regs.append(reg)
|
||||||
|
|
||||||
|
# Call function
|
||||||
|
self.emit(f" call {expr.name}")
|
||||||
|
|
||||||
|
# Get return value (it's now on top of stack)
|
||||||
|
self.emit(f" pop {temp_reg}")
|
||||||
|
|
||||||
|
# Clean up remaining args
|
||||||
|
for i in range(len(arg_regs) - 1):
|
||||||
|
self.emit(f" pop zero")
|
||||||
|
|
||||||
|
# Free the arg registers
|
||||||
|
for reg in arg_regs:
|
||||||
|
self.free_register(reg)
|
||||||
|
|
||||||
|
return temp_reg
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Unknown expression type: {type(expr)}")
|
||||||
|
|
||||||
|
def generate_binary_op(self, expr: BinaryOp) -> str:
|
||||||
|
# For operations that might contain function calls, we need to be careful
|
||||||
|
# about register allocation. Evaluate left, save it, evaluate right.
|
||||||
|
left_reg = self.generate_expression(expr.left)
|
||||||
|
|
||||||
|
# If right side contains a function call, we need to save left_reg
|
||||||
|
# For now, always save to be safe
|
||||||
|
saved_reg = self.allocate_register()
|
||||||
|
self.emit(f" mov {left_reg}, {saved_reg}")
|
||||||
|
self.free_register(left_reg)
|
||||||
|
|
||||||
|
right_reg = self.generate_expression(expr.right)
|
||||||
|
result_reg = self.allocate_register()
|
||||||
|
|
||||||
|
if expr.op == "+":
|
||||||
|
self.emit(f" add {left_reg}, {right_reg}, {result_reg}")
|
||||||
|
elif expr.op == "-":
|
||||||
|
self.emit(f" sub {left_reg}, {right_reg}, {result_reg}")
|
||||||
|
elif expr.op == "*":
|
||||||
|
# Simple multiplication using loop
|
||||||
|
temp_label = self.new_label("mult")
|
||||||
|
end_label = self.new_label("mult_end")
|
||||||
|
self.emit(f" lli 0, {result_reg}")
|
||||||
|
self.emit(f"{temp_label}:")
|
||||||
|
self.emit(f" cmp {right_reg}, zero")
|
||||||
|
self.emit(f" jeq {end_label}")
|
||||||
|
self.emit(f" add {result_reg}, {left_reg}, {result_reg}")
|
||||||
|
self.emit(f" dec {right_reg}")
|
||||||
|
self.emit(f" jmp {temp_label}")
|
||||||
|
self.emit(f"{end_label}:")
|
||||||
|
elif expr.op == "/":
|
||||||
|
# Simple division using loop
|
||||||
|
temp_label = self.new_label("div")
|
||||||
|
end_label = self.new_label("div_end")
|
||||||
|
self.emit(f" lli 0, {result_reg}")
|
||||||
|
self.emit(f"{temp_label}:")
|
||||||
|
self.emit(f" cmp {left_reg}, {right_reg}")
|
||||||
|
self.emit(f" jlt {end_label}")
|
||||||
|
self.emit(f" sub {left_reg}, {right_reg}, {left_reg}")
|
||||||
|
self.emit(f" inc {result_reg}")
|
||||||
|
self.emit(f" jmp {temp_label}")
|
||||||
|
self.emit(f"{end_label}:")
|
||||||
|
elif expr.op in ["==", "!=", "<", ">", "<=", ">="]:
|
||||||
|
self.emit(f" cmp {left_reg}, {right_reg}")
|
||||||
|
|
||||||
|
# Result is 1 if condition true, 0 otherwise
|
||||||
|
self.emit(f" lli 0, {result_reg}")
|
||||||
|
true_label = self.new_label("cmp_true")
|
||||||
|
end_label = self.new_label("cmp_end")
|
||||||
|
|
||||||
|
if expr.op == "==":
|
||||||
|
self.emit(f" jeq {true_label}")
|
||||||
|
elif expr.op == "!=":
|
||||||
|
self.emit(f" jne {true_label}")
|
||||||
|
elif expr.op == "<":
|
||||||
|
self.emit(f" jlt {true_label}")
|
||||||
|
elif expr.op == ">":
|
||||||
|
self.emit(f" jgt {true_label}")
|
||||||
|
elif expr.op == "<=":
|
||||||
|
self.emit(f" jle {true_label}")
|
||||||
|
elif expr.op == ">=":
|
||||||
|
self.emit(f" jge {true_label}")
|
||||||
|
|
||||||
|
self.emit(f" jmp {end_label}")
|
||||||
|
self.emit(f"{true_label}:")
|
||||||
|
self.emit(f" lli 1, {result_reg}")
|
||||||
|
self.emit(f"{end_label}:")
|
||||||
|
|
||||||
|
self.free_register(left_reg)
|
||||||
|
self.free_register(right_reg)
|
||||||
|
return result_reg
|
||||||
|
|
||||||
|
|
||||||
|
def compile_c_to_asm(source: str) -> str:
|
||||||
|
"""Compile C source code to DSA assembly."""
|
||||||
|
lexer = Lexer(source)
|
||||||
|
tokens = lexer.tokenize()
|
||||||
|
|
||||||
|
parser = Parser(tokens)
|
||||||
|
ast = parser.parse()
|
||||||
|
|
||||||
|
codegen = CodeGenerator()
|
||||||
|
assembly = codegen.generate(ast)
|
||||||
|
|
||||||
|
return assembly
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python compiler.py <input.c> [output.dsa]")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
input_file = sys.argv[1]
|
||||||
|
output_file = sys.argv[2] if len(sys.argv) > 2 else input_file.replace(".c", ".dsa")
|
||||||
|
|
||||||
|
with open(input_file, "r") as f:
|
||||||
|
source = f.read()
|
||||||
|
|
||||||
|
try:
|
||||||
|
assembly = compile_c_to_asm(source)
|
||||||
|
|
||||||
|
with open(output_file, "w") as f:
|
||||||
|
f.write(assembly)
|
||||||
|
|
||||||
|
print(f"Successfully compiled {input_file} to {output_file}")
|
||||||
|
except (SyntaxError, RuntimeError) as e:
|
||||||
|
print(f"Compilation error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
# # Example usage
|
||||||
|
# if len(sys.argv) > 1:
|
||||||
|
# example_c = sys.argv[1]
|
||||||
|
|
||||||
|
# else:
|
||||||
|
# example_c = """
|
||||||
|
# int factorial(int n) {
|
||||||
|
# if (n <= 1) {
|
||||||
|
# return 1;
|
||||||
|
# }
|
||||||
|
# return n * factorial(n - 1);
|
||||||
|
# }
|
||||||
|
|
||||||
|
# int main() {
|
||||||
|
# int result;
|
||||||
|
# result = factorial(5);
|
||||||
|
# return result;
|
||||||
|
# }
|
||||||
|
# """
|
||||||
|
|
||||||
|
# print("Example C program:")
|
||||||
|
# print(example_c)
|
||||||
|
# print("\n" + "="*60 + "\n")
|
||||||
|
# print("Generated DSA assembly:")
|
||||||
|
# print(compile_c_to_asm(example_c))
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
use crate::parser::Program;
|
||||||
|
|
||||||
|
pub struct CodeGenerator;
|
||||||
|
|
||||||
|
impl CodeGenerator {
|
||||||
|
pub fn new(ast: Program) -> Self {
|
||||||
|
CodeGenerator {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) -> Result<String, String> {
|
||||||
|
Ok(String::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
// ============================================================================
|
||||||
|
// Token Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum TokenType {
|
||||||
|
// Keywords
|
||||||
|
Int,
|
||||||
|
If,
|
||||||
|
Else,
|
||||||
|
While,
|
||||||
|
Return,
|
||||||
|
|
||||||
|
// Identifiers and literals
|
||||||
|
Identifier(String),
|
||||||
|
Number(i32),
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
Star,
|
||||||
|
Slash,
|
||||||
|
Assign,
|
||||||
|
Eq,
|
||||||
|
Ne,
|
||||||
|
Lt,
|
||||||
|
Gt,
|
||||||
|
Le,
|
||||||
|
Ge,
|
||||||
|
|
||||||
|
// Delimiters
|
||||||
|
LParen,
|
||||||
|
RParen,
|
||||||
|
LBrace,
|
||||||
|
RBrace,
|
||||||
|
Semicolon,
|
||||||
|
Comma,
|
||||||
|
|
||||||
|
Eof,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Token {
|
||||||
|
pub token_type: TokenType,
|
||||||
|
pub line: usize,
|
||||||
|
pub col: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Token {
|
||||||
|
pub fn new(token_type: TokenType, line: usize, col: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
token_type,
|
||||||
|
line,
|
||||||
|
col,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Lexer
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
pub struct Lexer {
|
||||||
|
source: Vec<char>,
|
||||||
|
pos: usize,
|
||||||
|
line: usize,
|
||||||
|
col: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Lexer {
|
||||||
|
pub fn new(source: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
source: source.chars().collect(),
|
||||||
|
pos: 0,
|
||||||
|
line: 1,
|
||||||
|
col: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error(&self, msg: &str) -> String {
|
||||||
|
format!(
|
||||||
|
"Lexer error at line {}, col {}: {}",
|
||||||
|
self.line, self.col, msg
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek(&self, offset: usize) -> Option<char> {
|
||||||
|
self.source.get(self.pos + offset).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance(&mut self) -> Option<char> {
|
||||||
|
if self.pos >= self.source.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let ch = self.source[self.pos];
|
||||||
|
self.pos += 1;
|
||||||
|
if ch == '\n' {
|
||||||
|
self.line += 1;
|
||||||
|
self.col = 1;
|
||||||
|
} else {
|
||||||
|
self.col += 1;
|
||||||
|
}
|
||||||
|
Some(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_whitespace(&mut self) {
|
||||||
|
while let Some(ch) = self.peek(0) {
|
||||||
|
if ch.is_whitespace() {
|
||||||
|
self.advance();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_comment(&mut self) {
|
||||||
|
if self.peek(0) == Some('/') && self.peek(1) == Some('/') {
|
||||||
|
while let Some(ch) = self.peek(0) {
|
||||||
|
if ch == '\n' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_number(&mut self) -> i32 {
|
||||||
|
let mut num_str = String::new();
|
||||||
|
while let Some(ch) = self.peek(0) {
|
||||||
|
if ch.is_ascii_digit() {
|
||||||
|
num_str.push(ch);
|
||||||
|
self.advance();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num_str.parse().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_identifier(&mut self) -> String {
|
||||||
|
let mut ident = String::new();
|
||||||
|
while let Some(ch) = self.peek(0) {
|
||||||
|
if ch.is_alphanumeric() || ch == '_' {
|
||||||
|
ident.push(ch);
|
||||||
|
self.advance();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ident
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tokenize(&mut self) -> Result<Vec<Token>, String> {
|
||||||
|
let mut tokens = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
self.skip_whitespace();
|
||||||
|
self.skip_comment();
|
||||||
|
|
||||||
|
if self.pos >= self.source.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let line = self.line;
|
||||||
|
let col = self.col;
|
||||||
|
let ch = self.peek(0).unwrap();
|
||||||
|
|
||||||
|
let token_type = if ch.is_ascii_digit() {
|
||||||
|
let num = self.read_number();
|
||||||
|
TokenType::Number(num)
|
||||||
|
} else if ch.is_alphabetic() || ch == '_' {
|
||||||
|
let ident = self.read_identifier();
|
||||||
|
match ident.as_str() {
|
||||||
|
"int" => TokenType::Int,
|
||||||
|
"if" => TokenType::If,
|
||||||
|
"else" => TokenType::Else,
|
||||||
|
"while" => TokenType::While,
|
||||||
|
"return" => TokenType::Return,
|
||||||
|
_ => TokenType::Identifier(ident),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match ch {
|
||||||
|
'=' if self.peek(1) == Some('=') => {
|
||||||
|
self.advance();
|
||||||
|
self.advance();
|
||||||
|
TokenType::Eq
|
||||||
|
}
|
||||||
|
'!' if self.peek(1) == Some('=') => {
|
||||||
|
self.advance();
|
||||||
|
self.advance();
|
||||||
|
TokenType::Ne
|
||||||
|
}
|
||||||
|
'<' if self.peek(1) == Some('=') => {
|
||||||
|
self.advance();
|
||||||
|
self.advance();
|
||||||
|
TokenType::Le
|
||||||
|
}
|
||||||
|
'>' if self.peek(1) == Some('=') => {
|
||||||
|
self.advance();
|
||||||
|
self.advance();
|
||||||
|
TokenType::Ge
|
||||||
|
}
|
||||||
|
'+' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::Plus
|
||||||
|
}
|
||||||
|
'-' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::Minus
|
||||||
|
}
|
||||||
|
'*' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::Star
|
||||||
|
}
|
||||||
|
'/' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::Slash
|
||||||
|
}
|
||||||
|
'=' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::Assign
|
||||||
|
}
|
||||||
|
'<' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::Lt
|
||||||
|
}
|
||||||
|
'>' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::Gt
|
||||||
|
}
|
||||||
|
'(' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::LParen
|
||||||
|
}
|
||||||
|
')' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::RParen
|
||||||
|
}
|
||||||
|
'{' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::LBrace
|
||||||
|
}
|
||||||
|
'}' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::RBrace
|
||||||
|
}
|
||||||
|
';' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::Semicolon
|
||||||
|
}
|
||||||
|
',' => {
|
||||||
|
self.advance();
|
||||||
|
TokenType::Comma
|
||||||
|
}
|
||||||
|
_ => return Err(self.error(&format!("Unexpected character: {}", ch))),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tokens.push(Token::new(token_type, line, col));
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.push(Token::new(TokenType::Eof, self.line, self.col));
|
||||||
|
Ok(tokens)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::{codegen::CodeGenerator, lexer::Lexer, parser::Parser};
|
||||||
|
|
||||||
|
pub mod codegen;
|
||||||
|
pub mod lexer;
|
||||||
|
pub mod parser;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Main & Tests
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// read from input file: syntax "c_compiler <src.c> [output.dsa]"
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
if args.len() < 2 {
|
||||||
|
eprintln!("Usage: c_compiler <src.c> [output.dsa]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let input_file = &args[1];
|
||||||
|
let output_file = if args.len() > 2 {
|
||||||
|
&args[2]
|
||||||
|
} else {
|
||||||
|
"output.dsa"
|
||||||
|
};
|
||||||
|
|
||||||
|
// read input
|
||||||
|
let input = std::fs::read_to_string(input_file).expect("Failed to read input file");
|
||||||
|
|
||||||
|
// Lexing
|
||||||
|
let mut lexer = Lexer::new(&input);
|
||||||
|
let tokens = match lexer.tokenize() {
|
||||||
|
Ok(tokens) => tokens,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Lexing error: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Tokens:");
|
||||||
|
for token in &tokens {
|
||||||
|
println!(" {:?}", token.token_type);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
|
||||||
|
// Parsing
|
||||||
|
let mut parser = Parser::new(tokens);
|
||||||
|
let ast = match parser.parse() {
|
||||||
|
Ok(ast) => ast,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Parsing error: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("AST:");
|
||||||
|
println!("{:#?}", ast);
|
||||||
|
|
||||||
|
// Code Gen
|
||||||
|
let mut generator = CodeGenerator::new(ast);
|
||||||
|
let result = match generator.run() {
|
||||||
|
Ok(code) => code,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Parsing error: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("CODE:");
|
||||||
|
println!("{:#?}", result);
|
||||||
|
}
|
||||||
@@ -0,0 +1,558 @@
|
|||||||
|
// ============================================================================
|
||||||
|
// AST Node Types
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::lexer::{Token, TokenType};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Program {
|
||||||
|
pub declarations: Vec<Declaration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Declaration {
|
||||||
|
Function {
|
||||||
|
name: String,
|
||||||
|
return_type: Type,
|
||||||
|
params: Vec<Parameter>,
|
||||||
|
body: Statement,
|
||||||
|
},
|
||||||
|
Variable {
|
||||||
|
name: String,
|
||||||
|
init: Option<Expression>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Parameter {
|
||||||
|
pub name: String,
|
||||||
|
pub param_type: Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Type {
|
||||||
|
Int,
|
||||||
|
Long,
|
||||||
|
Float,
|
||||||
|
Double,
|
||||||
|
Char,
|
||||||
|
Void,
|
||||||
|
Ptr(Box<Type>),
|
||||||
|
Array(Box<Type>, usize),
|
||||||
|
Struct(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Statement {
|
||||||
|
Compound {
|
||||||
|
statements: Vec<Statement>,
|
||||||
|
},
|
||||||
|
Assign {
|
||||||
|
// left side
|
||||||
|
name: String,
|
||||||
|
declare_type: Option<Type>,
|
||||||
|
|
||||||
|
// right side
|
||||||
|
value: Option<Box<Expression>>,
|
||||||
|
},
|
||||||
|
Expression {
|
||||||
|
expr: Expression,
|
||||||
|
},
|
||||||
|
If {
|
||||||
|
condition: Expression,
|
||||||
|
then_stmt: Box<Statement>,
|
||||||
|
else_stmt: Option<Box<Statement>>,
|
||||||
|
},
|
||||||
|
While {
|
||||||
|
condition: Expression,
|
||||||
|
body: Box<Statement>,
|
||||||
|
},
|
||||||
|
Return {
|
||||||
|
expr: Option<Expression>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Expression {
|
||||||
|
Empty,
|
||||||
|
Binary {
|
||||||
|
op: BinaryOperator,
|
||||||
|
left: Box<Expression>,
|
||||||
|
right: Box<Expression>,
|
||||||
|
},
|
||||||
|
Unary {
|
||||||
|
op: UnaryOperator,
|
||||||
|
operand: Box<Expression>,
|
||||||
|
},
|
||||||
|
Variable {
|
||||||
|
name: String,
|
||||||
|
expr_type: Option<Type>,
|
||||||
|
},
|
||||||
|
Number {
|
||||||
|
value: i32,
|
||||||
|
},
|
||||||
|
Call {
|
||||||
|
name: String,
|
||||||
|
args: Vec<Expression>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum BinaryOperator {
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Eq,
|
||||||
|
Ne,
|
||||||
|
Lt,
|
||||||
|
Gt,
|
||||||
|
Le,
|
||||||
|
Ge,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BinaryOperator {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
BinaryOperator::Add => write!(f, "+"),
|
||||||
|
BinaryOperator::Sub => write!(f, "-"),
|
||||||
|
BinaryOperator::Mul => write!(f, "*"),
|
||||||
|
BinaryOperator::Div => write!(f, "/"),
|
||||||
|
BinaryOperator::Eq => write!(f, "=="),
|
||||||
|
BinaryOperator::Ne => write!(f, "!="),
|
||||||
|
BinaryOperator::Lt => write!(f, "<"),
|
||||||
|
BinaryOperator::Gt => write!(f, ">"),
|
||||||
|
BinaryOperator::Le => write!(f, "<="),
|
||||||
|
BinaryOperator::Ge => write!(f, ">="),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum UnaryOperator {
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for UnaryOperator {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
UnaryOperator::Plus => write!(f, "+"),
|
||||||
|
UnaryOperator::Minus => write!(f, "-"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Parser
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
pub struct Parser {
|
||||||
|
tokens: Vec<Token>,
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub fn new(tokens: Vec<Token>) -> Self {
|
||||||
|
Self { tokens, pos: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error(&self, msg: &str) -> String {
|
||||||
|
let token = self.current();
|
||||||
|
format!(
|
||||||
|
"Parser error at line {}, col {}: {}",
|
||||||
|
token.line, token.col, msg
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current(&self) -> &Token {
|
||||||
|
self.tokens
|
||||||
|
.get(self.pos)
|
||||||
|
.unwrap_or_else(|| self.tokens.last().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek(&self, offset: usize) -> &Token {
|
||||||
|
self.tokens
|
||||||
|
.get(self.pos + offset)
|
||||||
|
.unwrap_or_else(|| self.tokens.last().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance(&mut self) -> &Token {
|
||||||
|
if self.pos < self.tokens.len() - 1 {
|
||||||
|
self.pos += 1;
|
||||||
|
}
|
||||||
|
self.current()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect(&mut self, expected: TokenType) -> Result<Token, String> {
|
||||||
|
let token = self.current().clone();
|
||||||
|
if std::mem::discriminant(&token.token_type) != std::mem::discriminant(&expected)
|
||||||
|
{
|
||||||
|
return Err(self.error(&format!(
|
||||||
|
"Expected {:?}, got {:?}",
|
||||||
|
expected, token.token_type
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
self.advance();
|
||||||
|
Ok(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(&mut self) -> Result<Program, String> {
|
||||||
|
let mut declarations = Vec::new();
|
||||||
|
|
||||||
|
while !matches!(self.current().token_type, TokenType::Eof) {
|
||||||
|
declarations.push(self.parse_declaration()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Program { declarations })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_declaration(&mut self) -> Result<Declaration, String> {
|
||||||
|
self.expect(TokenType::Int)?;
|
||||||
|
|
||||||
|
let name = match &self.current().token_type {
|
||||||
|
TokenType::Identifier(s) => s.clone(),
|
||||||
|
_ => return Err(self.error("Expected identifier")),
|
||||||
|
};
|
||||||
|
self.advance();
|
||||||
|
|
||||||
|
match &self.current().token_type {
|
||||||
|
TokenType::LParen => {
|
||||||
|
// Function declaration
|
||||||
|
self.advance();
|
||||||
|
let mut params = Vec::<Parameter>::new();
|
||||||
|
|
||||||
|
if !matches!(self.current().token_type, TokenType::RParen) {
|
||||||
|
self.expect(TokenType::Int)?;
|
||||||
|
|
||||||
|
match &self.current().token_type {
|
||||||
|
TokenType::Identifier(s) => {
|
||||||
|
params.push(Parameter {
|
||||||
|
name: s.clone(),
|
||||||
|
param_type: Type::Int,
|
||||||
|
});
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
_ => return Err(self.error("Expected parameter name")),
|
||||||
|
}
|
||||||
|
|
||||||
|
while matches!(self.current().token_type, TokenType::Comma) {
|
||||||
|
self.advance();
|
||||||
|
self.expect(TokenType::Int)?;
|
||||||
|
|
||||||
|
match &self.current().token_type {
|
||||||
|
TokenType::Identifier(s) => {
|
||||||
|
params.push(Parameter {
|
||||||
|
name: s.clone(),
|
||||||
|
param_type: Type::Int,
|
||||||
|
});
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
_ => return Err(self.error("Expected parameter name")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.expect(TokenType::RParen)?;
|
||||||
|
let body = self.parse_compound_stmt()?;
|
||||||
|
|
||||||
|
Ok(Declaration::Function {
|
||||||
|
name,
|
||||||
|
params,
|
||||||
|
body,
|
||||||
|
return_type: Type::Int,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Variable declaration
|
||||||
|
let init = if matches!(self.current().token_type, TokenType::Assign) {
|
||||||
|
self.advance();
|
||||||
|
Some(self.parse_expression()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
self.expect(TokenType::Semicolon)?;
|
||||||
|
Ok(Declaration::Variable { name, init })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_compound_stmt(&mut self) -> Result<Statement, String> {
|
||||||
|
self.expect(TokenType::LBrace)?;
|
||||||
|
let mut statements = Vec::new();
|
||||||
|
|
||||||
|
while !matches!(self.current().token_type, TokenType::RBrace) {
|
||||||
|
statements.push(self.parse_statement()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.expect(TokenType::RBrace)?;
|
||||||
|
Ok(Statement::Compound { statements })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_statement(&mut self) -> Result<Statement, String> {
|
||||||
|
match &self.current().token_type {
|
||||||
|
TokenType::LBrace => Ok(self.parse_compound_stmt()?),
|
||||||
|
TokenType::If => self.parse_if_stmt(),
|
||||||
|
TokenType::While => self.parse_while_stmt(),
|
||||||
|
TokenType::Return => self.parse_return_stmt(),
|
||||||
|
TokenType::Identifier(name) => {
|
||||||
|
let name = name.clone();
|
||||||
|
|
||||||
|
// peek ahead for open paren (func call expr)
|
||||||
|
if matches!(self.peek(1).token_type, TokenType::LParen) {
|
||||||
|
let expr = self.parse_expression()?; // a function call expr
|
||||||
|
self.expect(TokenType::Semicolon)?;
|
||||||
|
return Ok(Statement::Expression { expr });
|
||||||
|
}
|
||||||
|
|
||||||
|
self.advance(); // advance past identifier
|
||||||
|
|
||||||
|
// assignment expression
|
||||||
|
if matches!(self.current().token_type, TokenType::Assign) {
|
||||||
|
self.advance();
|
||||||
|
let expr = self.parse_expression()?;
|
||||||
|
|
||||||
|
self.expect(TokenType::Semicolon)?;
|
||||||
|
Ok(Statement::Assign {
|
||||||
|
name,
|
||||||
|
value: Some(Box::new(expr)),
|
||||||
|
declare_type: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// var expression
|
||||||
|
else {
|
||||||
|
self.expect(TokenType::Semicolon)?;
|
||||||
|
Ok(Statement::Expression {
|
||||||
|
expr: Expression::Variable {
|
||||||
|
name,
|
||||||
|
expr_type: None,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TokenType::Int => {
|
||||||
|
// Local variable declaration
|
||||||
|
self.advance();
|
||||||
|
let name = match &self.current().token_type {
|
||||||
|
TokenType::Identifier(s) => s.clone(),
|
||||||
|
_ => return Err(self.error("Expected variable name")),
|
||||||
|
};
|
||||||
|
self.advance();
|
||||||
|
|
||||||
|
let init = if matches!(self.current().token_type, TokenType::Assign) {
|
||||||
|
self.advance();
|
||||||
|
Some(self.parse_expression()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
self.expect(TokenType::Semicolon)?;
|
||||||
|
|
||||||
|
// Convert to assignment expression statement
|
||||||
|
let expr = if let Some(init_expr) = init {
|
||||||
|
Statement::Assign {
|
||||||
|
name,
|
||||||
|
value: Some(Box::new(init_expr)),
|
||||||
|
declare_type: Some(Type::Int),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Statement::Assign {
|
||||||
|
name,
|
||||||
|
value: None,
|
||||||
|
declare_type: Some(Type::Int),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let expr = if matches!(self.current().token_type, TokenType::Semicolon) {
|
||||||
|
Expression::Empty
|
||||||
|
} else {
|
||||||
|
self.parse_expression()?
|
||||||
|
};
|
||||||
|
|
||||||
|
self.expect(TokenType::Semicolon)?;
|
||||||
|
Ok(Statement::Expression { expr })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_if_stmt(&mut self) -> Result<Statement, String> {
|
||||||
|
self.expect(TokenType::If)?;
|
||||||
|
self.expect(TokenType::LParen)?;
|
||||||
|
let condition = self.parse_expression()?;
|
||||||
|
self.expect(TokenType::RParen)?;
|
||||||
|
let then_stmt = Box::new(self.parse_statement()?);
|
||||||
|
|
||||||
|
let else_stmt = if matches!(self.current().token_type, TokenType::Else) {
|
||||||
|
self.advance();
|
||||||
|
Some(Box::new(self.parse_statement()?))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Statement::If {
|
||||||
|
condition,
|
||||||
|
then_stmt,
|
||||||
|
else_stmt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_while_stmt(&mut self) -> Result<Statement, String> {
|
||||||
|
self.expect(TokenType::While)?;
|
||||||
|
self.expect(TokenType::LParen)?;
|
||||||
|
let condition = self.parse_expression()?;
|
||||||
|
self.expect(TokenType::RParen)?;
|
||||||
|
let body = Box::new(self.parse_statement()?);
|
||||||
|
|
||||||
|
Ok(Statement::While { condition, body })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_return_stmt(&mut self) -> Result<Statement, String> {
|
||||||
|
self.expect(TokenType::Return)?;
|
||||||
|
|
||||||
|
let expr = if matches!(self.current().token_type, TokenType::Semicolon) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.parse_expression()?)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.expect(TokenType::Semicolon)?;
|
||||||
|
Ok(Statement::Return { expr })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_expression(&mut self) -> Result<Expression, String> {
|
||||||
|
self.parse_comparison()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_comparison(&mut self) -> Result<Expression, String> {
|
||||||
|
let mut expr = self.parse_additive()?;
|
||||||
|
|
||||||
|
while let Some(op) = match &self.current().token_type {
|
||||||
|
TokenType::Eq => Some(BinaryOperator::Eq),
|
||||||
|
TokenType::Ne => Some(BinaryOperator::Ne),
|
||||||
|
TokenType::Lt => Some(BinaryOperator::Lt),
|
||||||
|
TokenType::Gt => Some(BinaryOperator::Gt),
|
||||||
|
TokenType::Le => Some(BinaryOperator::Le),
|
||||||
|
TokenType::Ge => Some(BinaryOperator::Ge),
|
||||||
|
_ => None,
|
||||||
|
} {
|
||||||
|
self.advance();
|
||||||
|
let right = Box::new(self.parse_additive()?);
|
||||||
|
expr = Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(expr),
|
||||||
|
right,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_additive(&mut self) -> Result<Expression, String> {
|
||||||
|
let mut expr = self.parse_multiplicative()?;
|
||||||
|
|
||||||
|
while let Some(op) = match &self.current().token_type {
|
||||||
|
TokenType::Plus => Some(BinaryOperator::Add),
|
||||||
|
TokenType::Minus => Some(BinaryOperator::Sub),
|
||||||
|
_ => None,
|
||||||
|
} {
|
||||||
|
self.advance();
|
||||||
|
let right = Box::new(self.parse_multiplicative()?);
|
||||||
|
expr = Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(expr),
|
||||||
|
right,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_multiplicative(&mut self) -> Result<Expression, String> {
|
||||||
|
let mut expr = self.parse_unary()?;
|
||||||
|
|
||||||
|
while let Some(op) = match &self.current().token_type {
|
||||||
|
TokenType::Star => Some(BinaryOperator::Mul),
|
||||||
|
TokenType::Slash => Some(BinaryOperator::Div),
|
||||||
|
_ => None,
|
||||||
|
} {
|
||||||
|
self.advance();
|
||||||
|
let right = Box::new(self.parse_unary()?);
|
||||||
|
expr = Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(expr),
|
||||||
|
right,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_unary(&mut self) -> Result<Expression, String> {
|
||||||
|
let op = match &self.current().token_type {
|
||||||
|
TokenType::Plus => Some(UnaryOperator::Plus),
|
||||||
|
TokenType::Minus => Some(UnaryOperator::Minus),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(op) = op {
|
||||||
|
self.advance();
|
||||||
|
let operand = Box::new(self.parse_unary()?);
|
||||||
|
return Ok(Expression::Unary { op, operand });
|
||||||
|
}
|
||||||
|
|
||||||
|
self.parse_primary()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_primary(&mut self) -> Result<Expression, String> {
|
||||||
|
match &self.current().token_type.clone() {
|
||||||
|
TokenType::Number(n) => {
|
||||||
|
let value = *n;
|
||||||
|
self.advance();
|
||||||
|
Ok(Expression::Number { value })
|
||||||
|
}
|
||||||
|
TokenType::Identifier(name) => {
|
||||||
|
let name = name.clone();
|
||||||
|
self.advance();
|
||||||
|
|
||||||
|
if matches!(self.current().token_type, TokenType::LParen) {
|
||||||
|
// Function call
|
||||||
|
self.advance();
|
||||||
|
let mut args = Vec::new();
|
||||||
|
|
||||||
|
if !matches!(self.current().token_type, TokenType::RParen) {
|
||||||
|
args.push(self.parse_expression()?);
|
||||||
|
|
||||||
|
while matches!(self.current().token_type, TokenType::Comma) {
|
||||||
|
self.advance();
|
||||||
|
args.push(self.parse_expression()?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.expect(TokenType::RParen)?;
|
||||||
|
Ok(Expression::Call { name, args })
|
||||||
|
} else {
|
||||||
|
Ok(Expression::Variable {
|
||||||
|
name,
|
||||||
|
expr_type: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TokenType::LParen => {
|
||||||
|
self.advance();
|
||||||
|
let expr = self.parse_expression()?;
|
||||||
|
self.expect(TokenType::RParen)?;
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
_ => Err(self.error(&format!(
|
||||||
|
"Unexpected token: {:?}",
|
||||||
|
self.current().token_type
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user