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:
parent
ca284482cb
commit
de1be1dc66
@ -10,12 +10,13 @@ import (
|
|||||||
|
|
||||||
struct Foo {}
|
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 struct IntegerExpr {
|
||||||
pub:
|
// pub:
|
||||||
val int
|
// val int
|
||||||
}
|
// }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
@ -45,6 +46,24 @@ pub:
|
|||||||
right Expr
|
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 {
|
struct IfExpr {
|
||||||
token token.Token
|
token token.Token
|
||||||
cond Expr
|
cond Expr
|
||||||
@ -57,29 +76,44 @@ struct ReturnStmt {
|
|||||||
results []Expr
|
results []Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
enum BinaryOp {
|
// string representaiton of expr
|
||||||
sum
|
pub fn (x Expr) str() string {
|
||||||
difference
|
match x {
|
||||||
product
|
BinaryExpr {
|
||||||
quotient
|
return '(${it.left.str()}$it.op.str()${it.right.str()})'
|
||||||
remainder
|
}
|
||||||
bitwise_and
|
ScalarExpr {
|
||||||
bitwise_or
|
return '${it.left.str()}$it.val'
|
||||||
bitwise_xor
|
}
|
||||||
left_shift
|
UnaryExpr {
|
||||||
right_shift
|
return '${it.left.str()}$it.op.str()'
|
||||||
|
}
|
||||||
equality
|
else { return '' }
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// }
|
||||||
|
@ -24,7 +24,8 @@ pub fn parse_expr(text string) ast.Expr {
|
|||||||
tok: res.tok
|
tok: res.tok
|
||||||
lit: res.lit
|
lit: res.lit
|
||||||
}
|
}
|
||||||
return p.expr()
|
// return p.expr()
|
||||||
|
return p.expr(token.lowest_prec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) next() {
|
fn (p mut Parser) next() {
|
||||||
@ -34,48 +35,43 @@ fn (p mut Parser) next() {
|
|||||||
p.lit = res.lit
|
p.lit = res.lit
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) expr() ast.Expr {
|
// Implementation of Pratt Precedence
|
||||||
//println('\n\nexpr()')
|
pub fn (p mut Parser) expr(rbp int) ast.Expr {
|
||||||
mut node := p.term()
|
// null denotation (prefix)
|
||||||
for p.tok == .plus || p.tok == .minus {
|
tok := p.tok
|
||||||
op := p.tok
|
lit := p.lit
|
||||||
p.next()
|
p.next()
|
||||||
node = ast.BinaryExpr {
|
mut left := ast.Expr{}
|
||||||
left: node
|
match tok {
|
||||||
op: op
|
.lpar {
|
||||||
right: p.term()
|
left = p.expr(0)
|
||||||
|
if p.tok != .rpar {
|
||||||
|
panic("Parse Error: expected )")
|
||||||
|
}
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (p mut Parser) term() ast.Expr {
|
// left binding power
|
||||||
mut node := p.factor()
|
for rbp < p.tok.precedence() {
|
||||||
for p.tok == .mul || p.tok == .div || p.tok == .mod {
|
tok2 := p.tok
|
||||||
op := p.tok
|
|
||||||
p.next()
|
p.next()
|
||||||
node = ast.BinaryExpr {
|
// left denotation (infix)
|
||||||
left: node
|
if tok2.is_right_assoc() {
|
||||||
op: op
|
left = ast.BinaryExpr{left: left, op: tok2, right: p.expr(tok2.precedence() - 1)}
|
||||||
right: p.factor()
|
}
|
||||||
|
if !tok2.is_right_assoc() && tok2.is_left_assoc() {
|
||||||
|
left = ast.BinaryExpr{left: left, op: tok2, right: p.expr(tok2.precedence())}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return node
|
return left
|
||||||
//return ast.BinaryExpr{}
|
|
||||||
//return ast.Expr.Binary(ast.BinaryExpr{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) factor() ast.Expr {
|
|
||||||
if p.tok == .number {
|
|
||||||
val := p.lit.int()
|
|
||||||
p.next()
|
|
||||||
return ast.IntegerExpr { val: val }
|
|
||||||
} else {
|
|
||||||
println('bad factor token')
|
|
||||||
println(p.tok)
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,19 +5,37 @@ import compiler2.ast
|
|||||||
fn test_parser() {
|
fn test_parser() {
|
||||||
//expr := ast.IntegerExpr {val:10}
|
//expr := ast.IntegerExpr {val:10}
|
||||||
//expr := ast.BinaryExpr{}
|
//expr := ast.BinaryExpr{}
|
||||||
|
|
||||||
|
// print using walk
|
||||||
expr := parse_expr('3 + 7')
|
expr := parse_expr('3 + 7')
|
||||||
walk(expr)
|
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) {
|
fn walk(node ast.Expr) {
|
||||||
//println('walk()')
|
//println('walk()')
|
||||||
match node {
|
match node {
|
||||||
ast.IntegerExpr {
|
|
||||||
print(it.val)
|
|
||||||
}
|
|
||||||
ast.BinaryExpr {
|
ast.BinaryExpr {
|
||||||
|
print(' (')
|
||||||
walk(it.left)
|
walk(it.left)
|
||||||
|
// print('$it.op.str()')
|
||||||
match it.op {
|
match it.op {
|
||||||
.plus {
|
.plus {
|
||||||
print(' + ')
|
print(' + ')
|
||||||
@ -29,7 +47,16 @@ fn walk(node ast.Expr) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
walk(it.right)
|
walk(it.right)
|
||||||
|
print(') ')
|
||||||
}
|
}
|
||||||
else {}
|
ast.ScalarExpr {
|
||||||
|
walk(it.left)
|
||||||
|
print(' $it.val ')
|
||||||
|
}
|
||||||
|
ast.UnaryExpr {
|
||||||
|
walk(it.left)
|
||||||
|
print(' $it.op ')
|
||||||
|
}
|
||||||
|
else { }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -303,3 +303,52 @@ pub fn (t Token) str() string {
|
|||||||
return token_str[int(t)]
|
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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user