compiler2: proof of concept cgen

pull/3219/head^2
Alexander Medvednikov 2019-12-24 20:54:43 +03:00
parent fe8a6abb41
commit 8d9f89e728
6 changed files with 193 additions and 21 deletions

View File

@ -980,6 +980,9 @@ fn (p mut Parser) fn_args(f mut Fn) {
p.next() p.next()
} }
} }
//if types_only && p.peek() == .lcbr {
//println('wtf')
//}
} }
// foo *(1, 2, 3, mut bar)* // foo *(1, 2, 3, mut bar)*

View File

@ -10,15 +10,19 @@ import (
struct Foo {} struct Foo {}
// pub type Expr = Foo | IfExpr | BinaryExpr | IntegerExpr pub type Expr = Foo | IfExpr | BinaryExpr | ScalarExpr | UnaryExpr |
pub type Expr = Foo | IfExpr | BinaryExpr | ScalarExpr | UnaryExpr StringLiteral | IntegerExpr
pub type Stmt = Foo | VarDecl
/*
pub struct IntegerExpr { pub struct IntegerExpr {
pub: pub:
val int val int
} }
*/
pub struct StringLiteral {
pub:
val string
}
/* /*
pub enum Expr { pub enum Expr {
@ -28,10 +32,24 @@ pub enum Expr {
} }
*/ */
/*
pub struct Stmt { pub struct Stmt {
pos int pos int
//end int //end int
} }
*/
pub struct VarDecl {
pub:
name string
expr Expr
}
pub struct Program {
pub:
exprs []Expr
}
// A single identifier // A single identifier
struct Ident { struct Ident {

View File

@ -0,0 +1,82 @@
module cgen
import (
strings
compiler2.ast
)
struct Gen {
out strings.Builder
}
pub fn gen(program ast.Program) {
mut g := Gen{out:strings.new_builder(100)}
for expr in program.exprs {
g.expr(expr)
g.writeln('')
}
println(g.out.str())
}
pub fn (g &Gen) save() {
}
pub fn (g mut Gen) write(s string) {
g.out.write(s)
}
pub fn (g mut Gen) writeln(s string) {
g.out.writeln(s)
}
struct Type {
name string
}
const (
string_type = Type{'string'}
int_type = Type{'int'}
void_type = Type{'void'}
)
fn (g mut Gen) expr(node ast.Expr) Type {
//println('cgen expr()')
match node {
ast.IntegerExpr {
g.write(it.val.str())
return int_type
}
ast.StringLiteral {
g.write('"$it.val"')
return string_type
}
ast.BinaryExpr {
typ := g.expr(it.left)
match it.op {
.plus { g.write(' + ') }
.minus { g.write(' - ') }
.mul { g.write(' * ') }
.div { g.write(' / ') }
else {}
}
typ2 := g.expr(it.right)
if typ.name != typ2.name {
println('bad types $typ.name $typ2.name')
}
return typ
}
ast.VarDecl {
g.write('var $it.name = ')
g.expr(it.expr)
g.writeln(';')
return void_type
}
else {
println('bad node')
}
}
return void_type
}

View File

@ -12,8 +12,8 @@ import (
struct Parser { struct Parser {
scanner &scanner.Scanner scanner &scanner.Scanner
mut: mut:
tok token.Token tok token.Token
lit string lit string
} }
pub fn parse_expr(text string) ast.Expr { pub fn parse_expr(text string) ast.Expr {
@ -28,10 +28,21 @@ pub fn parse_expr(text string) ast.Expr {
return p.expr(token.lowest_prec) return p.expr(token.lowest_prec)
} }
pub fn parse_stmt(text string) ast.Stmt {
mut s := scanner.new_scanner(text)
res := s.scan()
mut p := Parser{
scanner: s
tok: res.tok
lit: res.lit
}
return p.stmt()
}
fn (p mut Parser) next() { fn (p mut Parser) next() {
res := p.scanner.scan() res := p.scanner.scan()
p.tok = res.tok p.tok = res.tok
//println(p.tok.str()) // println(p.tok.str())
p.lit = res.lit p.lit = res.lit
} }
@ -41,37 +52,76 @@ pub fn (p mut Parser) expr(rbp int) ast.Expr {
tok := p.tok tok := p.tok
lit := p.lit lit := p.lit
p.next() p.next()
mut left := ast.Expr{} mut node := ast.Expr{
}
match tok { match tok {
.lpar { .lpar {
left = p.expr(0) node = p.expr(0)
if p.tok != .rpar { if p.tok != .rpar {
panic("Parse Error: expected )") panic('Parse Error: expected )')
} }
p.next() p.next()
} }
else { else {
// TODO: fix bug. note odd conditon instead of else if (same below) // TODO: fix bug. note odd conditon instead of else if (same below)
if tok.is_scalar() { if tok.is_scalar() {
left = ast.ScalarExpr{val: lit, typ: tok} node = ast.ScalarExpr{
val: lit
typ: tok
}
} }
if !tok.is_scalar() && tok.is_unary() { if !tok.is_scalar() && tok.is_unary() {
left = ast.UnaryExpr{left: p.expr(token.highest_prec), op: tok} node = ast.UnaryExpr{
left: p.expr(token.highest_prec)
op: tok
}
} }
} }}
}
// left binding power // left binding power
for rbp < p.tok.precedence() { for rbp < p.tok.precedence() {
tok2 := p.tok tok2 := p.tok
p.next() p.next()
// left denotation (infix) // left denotation (infix)
if tok2.is_right_assoc() { if tok2.is_right_assoc() {
left = ast.BinaryExpr{left: left, op: tok2, right: p.expr(tok2.precedence() - 1)} node = ast.BinaryExpr{
left: node
op: tok2
right: p.expr(tok2.precedence() - 1)
}
} }
if !tok2.is_right_assoc() && tok2.is_left_assoc() { if !tok2.is_right_assoc() && tok2.is_left_assoc() {
left = ast.BinaryExpr{left: left, op: tok2, right: p.expr(tok2.precedence())} node = ast.BinaryExpr{
left: node
op: tok2
right: p.expr(tok2.precedence())
}
} }
} }
return left return node
}
fn (p mut Parser) stmt() ast.Stmt {
if p.tok == .name {
name := p.lit
p.next()
if p.tok == .decl_assign {
p.next()
return ast.VarDecl{
name: name
expr: p.expr(token.lowest_prec)
}
}
}
/*
match node {
Ident {
}
}
*/
return ast.VarDecl{
}
} }

View File

@ -1,6 +1,9 @@
module parser module parser
import compiler2.ast import (
compiler2.ast
compiler2.cgen
)
fn test_parser() { fn test_parser() {
//expr := ast.IntegerExpr {val:10} //expr := ast.IntegerExpr {val:10}
@ -10,7 +13,7 @@ fn test_parser() {
expr := parse_expr('3 + 7') expr := parse_expr('3 + 7')
walk(expr) walk(expr)
println('\n') println('\n')
text_expr := [ text_expr := [
'1 += 2', '1 += 2',
'1.2 + 3.4', '1.2 + 3.4',
@ -62,4 +65,17 @@ fn walk(node ast.Expr) {
} }
else { } else { }
} }
} /*
//expr := parse_expr('3 + 7 * 2')
expr := parse_stmt('a := 3 + "f"')
program := ast.Program{
exprs: [
expr,
//parse_expr('2 * 2'),
]
}
cgen.gen(program)
//cgen.save()
*/
}

View File

@ -29,6 +29,9 @@ pub fn (b mut Builder) write_b(data byte) {
} }
pub fn (b mut Builder) write(s string) { pub fn (b mut Builder) write(s string) {
if s == '' {
return
}
b.buf.push_many(s.str, s.len) b.buf.push_many(s.str, s.len)
// for c in s { // for c in s {
// b.buf << c // b.buf << c