basic One2C code gen
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,6 +6,8 @@ onev
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
*.c
|
||||
*.one
|
||||
|
||||
# Ignore binary output folders
|
||||
bin/
|
||||
|
||||
132
generator.v
Normal file
132
generator.v
Normal file
@@ -0,0 +1,132 @@
|
||||
module main
|
||||
|
||||
import strings
|
||||
import os
|
||||
|
||||
struct Generator {
|
||||
mut:
|
||||
out strings.Builder
|
||||
}
|
||||
|
||||
fn (mut g Generator) get_c_type(typ string) string {
|
||||
c_type := if typ == 'real' { 'double' } else { typ }
|
||||
return c_type
|
||||
}
|
||||
|
||||
fn (mut g Generator) gen_stmt(stmt Stmt) {
|
||||
match stmt {
|
||||
VarDecl {
|
||||
c_type := g.get_c_type(stmt.type)
|
||||
g.out.write_string('${c_type} ${stmt.name} = ')
|
||||
g.gen_expr(stmt.value)
|
||||
g.out.writeln(';')
|
||||
}
|
||||
ExprStmt {
|
||||
g.gen_expr(stmt.expr)
|
||||
g.out.writeln(';')
|
||||
}
|
||||
ReturnStmt {
|
||||
g.out.write_string('return ')
|
||||
g.gen_expr(stmt.expr)
|
||||
g.out.writeln(';')
|
||||
}
|
||||
Block {
|
||||
g.out.writeln('{')
|
||||
for inner_stmt in stmt.stmts {
|
||||
g.gen_stmt(inner_stmt)
|
||||
}
|
||||
g.out.writeln('}')
|
||||
}
|
||||
FuncDecl {
|
||||
c_type := g.get_c_type(stmt.ret_type)
|
||||
g.out.write_string('${c_type} ${stmt.name}() ')
|
||||
g.gen_stmt(stmt.block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Generator) gen_expr(expr Expr) {
|
||||
match expr {
|
||||
RealLiteral {
|
||||
g.out.write_string(expr.val.str())
|
||||
}
|
||||
IntegerLiteral {
|
||||
g.out.write_string(expr.val.str())
|
||||
}
|
||||
BoolLiteral {
|
||||
g.out.write_string(expr.val.str())
|
||||
}
|
||||
Variable {
|
||||
g.out.write_string(expr.name)
|
||||
}
|
||||
UnaryExpr {
|
||||
// Handle postfix/prefix logic if necessary
|
||||
g.out.write_string('${expr.ident}${expr.op}')
|
||||
}
|
||||
BinaryExpr {
|
||||
g.out.write_string('(')
|
||||
g.gen_expr(expr.left)
|
||||
g.out.write_string(' ${expr.op} ')
|
||||
g.gen_expr(expr.right)
|
||||
g.out.write_string(')')
|
||||
}
|
||||
PrintExpr {
|
||||
g.out.write_string('printf(\"%')
|
||||
format := match expr.type {
|
||||
'int' {'d'}
|
||||
'real' {'lf'}
|
||||
'bool' {'d'}
|
||||
else {panic("Tried printing illegal type")}
|
||||
}
|
||||
g.out.write_string('${format}\\n\", ')
|
||||
g.gen_expr(expr.expr)
|
||||
g.out.write_string(')')
|
||||
}
|
||||
TypeCast {
|
||||
c_type := g.get_c_type(expr.type)
|
||||
g.out.write_string('(${c_type})')
|
||||
g.gen_expr(expr.expr)
|
||||
}
|
||||
else {panic('unimplemented ${expr}')}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Generator) gen_c(program []Stmt) string {
|
||||
g.out.writeln('#include <stdio.h>')
|
||||
g.out.writeln('#include <stdbool.h>') // For your 'bool' types [cite: 4]
|
||||
for stmt in program {
|
||||
g.gen_stmt(stmt)
|
||||
}
|
||||
|
||||
return g.out.str()
|
||||
|
||||
}
|
||||
|
||||
fn compile_with_clang(c_code string, output_name string, keep_c bool) {
|
||||
// 1. Write the C code to a temporary file
|
||||
c_file := 'middle_c.c'
|
||||
os.write_file(c_file, c_code) or {
|
||||
eprintln('Failed to write C file: $err')
|
||||
return
|
||||
}
|
||||
|
||||
// 2. Construct the clang command
|
||||
// We'll use -O2 for optimization and -o to specify the output binary
|
||||
clang_cmd := 'clang ${c_file} -o ${output_name} -O2'
|
||||
|
||||
println('Executing: ${clang_cmd}')
|
||||
|
||||
// 3. Run the command
|
||||
result := os.execute(clang_cmd)
|
||||
|
||||
if result.exit_code != 0 {
|
||||
eprintln('Clang Compilation Failed:')
|
||||
eprintln(result.output)
|
||||
} else {
|
||||
println('Compilation successful! Binary created: $output_name')
|
||||
// Optional: Remove the temporary C file
|
||||
if !keep_c {
|
||||
os.rm(c_file) or { }
|
||||
}
|
||||
}
|
||||
}
|
||||
4
lexer.v
4
lexer.v
@@ -11,6 +11,7 @@ enum TokenType as u8 {
|
||||
kw_break
|
||||
kw_fn
|
||||
kw_return
|
||||
kw_print
|
||||
integer
|
||||
real
|
||||
boolean
|
||||
@@ -99,6 +100,7 @@ fn toktype_from_kw(kw string) TokenType {
|
||||
'fn' {.kw_fn}
|
||||
'return' {.kw_return}
|
||||
'true', 'false' {.boolean}
|
||||
'print' {.kw_print}
|
||||
else {.unknown}
|
||||
}
|
||||
}
|
||||
@@ -114,7 +116,7 @@ fn is_real(str string) bool {
|
||||
|
||||
fn is_keyword(str string) bool {
|
||||
return [
|
||||
"void", "int", "real", "bool", "if", "else", "for", "break", "fn", "return", "let", "true", "false"
|
||||
"void", "int", "real", "bool", "if", "else", "for", "break", "fn", "return", "let", "true", "false", "print"
|
||||
].contains(str)
|
||||
}
|
||||
|
||||
|
||||
14
main.v
14
main.v
@@ -1,9 +1,10 @@
|
||||
module main
|
||||
|
||||
import os
|
||||
import strings
|
||||
|
||||
fn main() {
|
||||
content := os.read_file("test.one") or { return }
|
||||
content := os.read_file("source.one") or { return }
|
||||
println("---------\n" + content + "---------")
|
||||
tokens := lex(content) or { return }
|
||||
println("-- TOK --")
|
||||
@@ -17,4 +18,15 @@ fn main() {
|
||||
|
||||
println("-- AST --")
|
||||
println(statements)
|
||||
|
||||
mut generator := Generator{
|
||||
out: strings.new_builder(100)
|
||||
}
|
||||
|
||||
out_c := generator.gen_c(statements)
|
||||
|
||||
println("--- C ---")
|
||||
println(out_c)
|
||||
compile_with_clang(out_c, 'test', true)
|
||||
|
||||
}
|
||||
|
||||
76
parser.v
76
parser.v
@@ -2,6 +2,28 @@ module main
|
||||
|
||||
import term
|
||||
|
||||
// ------------------------------------------- Precedence
|
||||
|
||||
enum Precedence {
|
||||
lowest
|
||||
assignment // = , +=, -=
|
||||
comparison // ==, !=, <, >
|
||||
sum // +, -
|
||||
product // *, /
|
||||
prefix // -x, !x
|
||||
call // function()
|
||||
}
|
||||
|
||||
fn (p Parser) get_precedence(tok_type TokenType) Precedence {
|
||||
return match tok_type {
|
||||
.equals, .plus_eq, .minus_eq, .star_eq, .slash_eq { .assignment }
|
||||
.eq_eq, .not_eq, .less_eq, .greater_eq { .comparison }
|
||||
.plus, .minus { .sum }
|
||||
.star, .slash { .product }
|
||||
else { .lowest }
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------- Symbol Table
|
||||
|
||||
type SymbolInfo = VarSymbolInfo | FuncSymbolInfo
|
||||
@@ -70,7 +92,7 @@ fn (mut s SymbolTable) is_in_global_scope() bool {
|
||||
|
||||
// ------------------------------------------- Expressions
|
||||
|
||||
type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | Variable | TypeExpr | Function | TypeCast | ParenExpr
|
||||
type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr
|
||||
|
||||
struct VoidExpr {}
|
||||
|
||||
@@ -118,6 +140,11 @@ struct ParenExpr {
|
||||
expr Expr
|
||||
}
|
||||
|
||||
struct PrintExpr {
|
||||
expr Expr
|
||||
type string
|
||||
}
|
||||
|
||||
// ------------------------------------------- Statements
|
||||
|
||||
type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | FuncDecl
|
||||
@@ -139,7 +166,7 @@ struct ExprStmt {
|
||||
}
|
||||
|
||||
struct ReturnStmt {
|
||||
value Expr
|
||||
expr Expr
|
||||
}
|
||||
|
||||
struct Block {
|
||||
@@ -210,20 +237,20 @@ fn (mut p Parser) parse_primary() Expr {
|
||||
.identifier {p.parse_ident(token.text)}
|
||||
.type {p.parse_type(token.text)}
|
||||
.lparen {p.parse_paren()}
|
||||
.kw_print {p.parse_print()}
|
||||
else {parse_error("Unexpected Token")}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) parse_expr() Expr {
|
||||
mut left := p.parse_primary()
|
||||
fn (mut p Parser) parse_expr(prec Precedence) Expr {
|
||||
mut expr := p.parse_primary()
|
||||
|
||||
match p.peek().type {
|
||||
.plus, .minus, .star, .slash, .equals, .eq_eq, .not_eq, .less_eq, .greater_eq,
|
||||
.plus_eq, .minus_eq, .star_eq, .slash_eq {
|
||||
return p.parse_binary(left, p.peek().text)
|
||||
}
|
||||
else {return left}
|
||||
for int(prec) < int(p.get_precedence(p.peek().type)) {
|
||||
op_tok := p.next()
|
||||
expr = p.parse_binary(expr, op_tok.text, p.get_precedence(op_tok.type))
|
||||
}
|
||||
|
||||
return expr
|
||||
}
|
||||
|
||||
fn (mut p Parser) parse_ident(ident string) Expr {
|
||||
@@ -233,10 +260,19 @@ fn (mut p Parser) parse_ident(ident string) Expr {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) parse_binary(left Expr, op string) BinaryExpr {
|
||||
p.next()
|
||||
right := p.parse_expr()
|
||||
fn (mut p Parser) parse_print() PrintExpr {
|
||||
p.expect(.lparen)
|
||||
expr := p.parse_expr(.lowest)
|
||||
p.expect(.rparen)
|
||||
return PrintExpr{expr: expr, type: p.get_expr_type(expr)}
|
||||
}
|
||||
|
||||
fn (mut p Parser) parse_binary(left Expr, op string, prec Precedence) BinaryExpr {
|
||||
//p.next()
|
||||
right := p.parse_expr(prec)
|
||||
binary_expr := BinaryExpr{left, op, right}
|
||||
|
||||
|
||||
if !p.is_op_valid_for_type(p.get_expr_type(left), op) {
|
||||
parse_error("Illegal operation ${op} for type ${p.get_expr_type(left)}")
|
||||
}
|
||||
@@ -248,7 +284,7 @@ fn (mut p Parser) parse_type(type string) Expr {
|
||||
|
||||
if p.peek().type == .lparen {
|
||||
p.next()
|
||||
expr := p.parse_expr()
|
||||
expr := p.parse_expr(.lowest)
|
||||
p.expect(.rparen)
|
||||
|
||||
return TypeCast {
|
||||
@@ -261,7 +297,7 @@ fn (mut p Parser) parse_type(type string) Expr {
|
||||
}
|
||||
|
||||
fn (mut p Parser) parse_paren() ParenExpr {
|
||||
expr := p.parse_expr()
|
||||
expr := p.parse_expr(.lowest)
|
||||
p.expect(.rparen)
|
||||
return ParenExpr{expr: expr}
|
||||
}
|
||||
@@ -356,7 +392,7 @@ fn (mut p Parser) parse_var_decl() VarDecl {
|
||||
}
|
||||
|
||||
p.expect(.equals)
|
||||
val := p.parse_expr()
|
||||
val := p.parse_expr(.lowest)
|
||||
|
||||
if type_tok.text == 'void' {
|
||||
parse_error("Cannot declare a variable of type void")
|
||||
@@ -402,9 +438,9 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
|
||||
return_stmts := p.get_return_stmts_recursive(block)
|
||||
|
||||
for return_stmt in return_stmts {
|
||||
if p.get_expr_type(return_stmt.value) != type_tok.text {
|
||||
if p.get_expr_type(return_stmt.expr) != type_tok.text {
|
||||
parse_error("Mismatch between declared return type (${type_tok.text}) \
|
||||
and actual return type (${p.get_expr_type(return_stmt.value)})")
|
||||
and actual return type (${p.get_expr_type(return_stmt.expr)})")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,12 +473,12 @@ fn (mut p Parser) parse_return_stmt() ReturnStmt {
|
||||
p.expect(.semicolon)
|
||||
}
|
||||
return ReturnStmt {
|
||||
value: expr
|
||||
expr: expr
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) parse_expr_stmt() ExprStmt {
|
||||
expr := p.parse_expr()
|
||||
expr := p.parse_expr(.lowest)
|
||||
p.expect(.semicolon)
|
||||
|
||||
return ExprStmt {
|
||||
|
||||
Reference in New Issue
Block a user