1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

compiler2: start implementing pratt style parser

This commit is contained in:
joe-conigliaro 2019-12-25 23:39:58 +11:00 committed by Alexander Medvednikov
parent ca284482cb
commit de1be1dc66
4 changed files with 180 additions and 74 deletions

View File

@ -10,12 +10,13 @@ import (
struct Foo {}
pub type Expr = Foo | IfExpr | BinaryExpr | IntegerExpr
// pub type Expr = Foo | IfExpr | BinaryExpr | IntegerExpr
pub type Expr = Foo | IfExpr | BinaryExpr | ScalarExpr | UnaryExpr
pub struct IntegerExpr {
pub:
val int
}
// pub struct IntegerExpr {
// pub:
// val int
// }
/*
pub enum Expr {
@ -45,6 +46,24 @@ pub:
right Expr
}
pub struct ScalarExpr {
pub:
token token.Token
// op BinaryOp
// op token.Token
typ token.Token
val string
left Expr
}
pub struct UnaryExpr {
pub:
// token token.Token
//op BinaryOp
op token.Token
left Expr
}
struct IfExpr {
token token.Token
cond Expr
@ -57,29 +76,44 @@ struct ReturnStmt {
results []Expr
}
enum BinaryOp {
sum
difference
product
quotient
remainder
bitwise_and
bitwise_or
bitwise_xor
left_shift
right_shift
equality
inequality
less_than
less_than_or_equal
more_than
more_than_or_equal
in_check
//These are suffixed with `bool` to prevent conflict with the keyword `or`
and_bool
or_bool
// string representaiton of expr
pub fn (x Expr) str() string {
match x {
BinaryExpr {
return '(${it.left.str()}$it.op.str()${it.right.str()})'
}
ScalarExpr {
return '${it.left.str()}$it.val'
}
UnaryExpr {
return '${it.left.str()}$it.op.str()'
}
else { return '' }
}
}
// enum BinaryOp {
// sum
// difference
// product
// quotient
// remainder
// bitwise_and
// bitwise_or
// bitwise_xor
// left_shift
// right_shift
// equality
// inequality
// less_than
// less_than_or_equal
// more_than
// more_than_or_equal
// in_check
// //These are suffixed with `bool` to prevent conflict with the keyword `or`
// and_bool
// or_bool
// }

View File

@ -24,7 +24,8 @@ pub fn parse_expr(text string) ast.Expr {
tok: res.tok
lit: res.lit
}
return p.expr()
// return p.expr()
return p.expr(token.lowest_prec)
}
fn (p mut Parser) next() {
@ -34,48 +35,43 @@ fn (p mut Parser) next() {
p.lit = res.lit
}
fn (p mut Parser) expr() ast.Expr {
//println('\n\nexpr()')
mut node := p.term()
for p.tok == .plus || p.tok == .minus {
op := p.tok
// Implementation of Pratt Precedence
pub fn (p mut Parser) expr(rbp int) ast.Expr {
// null denotation (prefix)
tok := p.tok
lit := p.lit
p.next()
node = ast.BinaryExpr {
left: node
op: op
right: p.term()
mut left := ast.Expr{}
match tok {
.lpar {
left = p.expr(0)
if p.tok != .rpar {
panic("Parse Error: expected )")
}
}
return node
}
fn (p mut Parser) term() ast.Expr {
mut node := p.factor()
for p.tok == .mul || p.tok == .div || p.tok == .mod {
op := p.tok
p.next()
node = ast.BinaryExpr {
left: node
op: op
right: p.factor()
}
else {
// TODO: fix bug. note odd conditon instead of else if (same below)
if tok.is_scalar() {
left = ast.ScalarExpr{val: lit, typ: tok}
}
if !tok.is_scalar() && tok.is_unary() {
left = ast.UnaryExpr{left: p.expr(token.highest_prec), op: tok}
}
}
}
return node
//return ast.BinaryExpr{}
//return ast.Expr.Binary(ast.BinaryExpr{})
}
fn (p mut Parser) factor() ast.Expr {
if p.tok == .number {
val := p.lit.int()
// left binding power
for rbp < p.tok.precedence() {
tok2 := p.tok
p.next()
return ast.IntegerExpr { val: val }
} else {
println('bad factor token')
println(p.tok)
exit(1)
// left denotation (infix)
if tok2.is_right_assoc() {
left = ast.BinaryExpr{left: left, op: tok2, right: p.expr(tok2.precedence() - 1)}
}
if !tok2.is_right_assoc() && tok2.is_left_assoc() {
left = ast.BinaryExpr{left: left, op: tok2, right: p.expr(tok2.precedence())}
}
}
return left
}

View File

@ -5,19 +5,37 @@ import compiler2.ast
fn test_parser() {
//expr := ast.IntegerExpr {val:10}
//expr := ast.BinaryExpr{}
// print using walk
expr := parse_expr('3 + 7')
walk(expr)
println('')
println('\n')
text_expr := [
'4 + 4',
'1 + 2 * 5',
'(2 * 3) / 2',
'3 + (7 * 6)',
'2 ^ 8 * (7 * 6)',
'(2) + (17*2-30) * (5)+2 - (8/2)*4'
]
for s in text_expr {
// print using str method
x := parse_expr(s)
println('source: $s')
println('parsed: $x')
println('===================')
}
}
fn walk(node ast.Expr) {
//println('walk()')
match node {
ast.IntegerExpr {
print(it.val)
}
ast.BinaryExpr {
print(' (')
walk(it.left)
// print('$it.op.str()')
match it.op {
.plus {
print(' + ')
@ -29,7 +47,16 @@ fn walk(node ast.Expr) {
}
walk(it.right)
print(') ')
}
else {}
ast.ScalarExpr {
walk(it.left)
print(' $it.val ')
}
ast.UnaryExpr {
walk(it.left)
print(' $it.op ')
}
else { }
}
}

View File

@ -303,3 +303,52 @@ pub fn (t Token) str() string {
return token_str[int(t)]
}
// Representation of highest and lowest precedence
const (
lowest_prec = 0
highest_prec = 7
)
// Precedence returns a tokens precedence if defined, otherwise lowest_prec
pub fn (tok Token) precedence() int {
match tok {
.plus, .minus { return 4 }
.mul, .div { return 4 }
.xor { return 6 }
.mod {return 7 }
else { return lowest_prec }
}
}
// is_scalar returns true if the token is a scalar
pub fn (tok Token) is_scalar() bool {
match tok {
.number { return true }
else { return false }
}
}
// is_unary returns true if the token can be in a unary expression
pub fn (tok Token) is_unary() bool {
match tok {
.plus, .minus { return true }
else { return false }
}
}
// is_left_assoc returns true if the token is left associative
pub fn (tok Token) is_left_assoc() bool {
match tok {
.number, .plus, .minus, .mul, .div, .mod { return true }
else { return false }
}
}
// is_right_assoc returns true if the token is right associative
pub fn (tok Token) is_right_assoc() bool {
match tok {
.xor { return true }
else { return false }
}
}