рджрдордореАрдЬрд╝ рдХреЗ рд▓рд┐рдП рдкреНрд░реИрдЯ рдкрд░реНрд╕рд░реНрд╕

рдкреБрдирд░рд╛рд╡рд░реНрддреА рд╡рдВрд╢ рдХрд╛рд░реНрдп рдЖрджрд░реНрд╢ рд░реВрдк рд╕реЗ рддрдм рд╣реЛрддрд╛ рд╣реИ рдЬрдм рдЖрдк рд╡рд░реНрддрдорд╛рди рд╕рдВрджрд░реНрдн рдФрд░ рдЯреЛрдХрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреЛрдб рдХреЗ рдПрдХ рдЯреБрдХрдбрд╝реЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд┐рд░реНрдгрдп рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


рднрд╛рд╡ рдЪрд┐рддреНрд░ рдХреЛ рдЦрд░рд╛рдм рдХрд░рддреЗ рд╣реИрдВ : рдкреЛрд╕реНрдЯрдлрд╝рд┐рдХреНрд╕, рдЗрдиреНрдлрд┐рдХреНрд╕ рдФрд░ рдЕрдиреНрдпред рд╕рдорд╕реНрдпрд╛: рдЖрдк рд╕рдордЭ рдирд╣реАрдВ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдЬрдм рддрдХ рдЖрдк рдЗрд╕рдХреА рдкрд╣рд▓реА рдЫрдорд╛рд╣реА рдХреЛ рдкрд╛рд░реНрд╕ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ рддрдм рддрдХ рдЖрдк рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХреА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдЕрдХреНрд╕рд░ рдСрдкрд░реЗрд╢рди рдХреА рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдФрд░ рдЗрд╕рдХреА рд╕рд╣рдпреЛрдЧреАрддрд╛ рдЖрдкрдХреЗ рд▓рд┐рдП рднреА рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рддрд╛рдХрд┐ рдирд┐рд░реНрдорд┐рдд рдПрдПрд╕рдЯреА рдореЗрдВ рд╕рд╣реА рд╕рдВрд░рдЪрдирд╛ рд╣реЛред


рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рдЧреЛ рдмреЛрд▓реА рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд╛рд░реНрд╕рд░ рд▓рд┐рдЦреЗрдВрдЧреЗ, рдЬрд┐рди рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдкрд░ рд╣рдо рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рдж рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдкреНрд░реИрдЯ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рд╣рдорд╛рд░реА рдЕрдзрд┐рдХрд╛рдВрд╢ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИред



рд╢рдмреНрджрд╛рд╡рд▓реА


. , , - .


: , (, ).
: , .
/expression: , . : .
Statement: , . : .
/precedence: .
: , . : x++.
: , . : ++x.
: , . : x+y.
/left-associative: .
/right-associative: .
non-associative: .
: , AST .
AST: , .
/: , .
: .
: .
: ().
: , .
: , .




рдЧреЛ ++ рдФрд░ ++ рдЧреЛ


рд╢рд╛рдмреНрджрд┐рдХ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдкрд░ рд╕рдордп рдмрд░реНрдмрд╛рдж рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП , рд╣рдо рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕реЗ рдЕрдкрдиреА рдЬрд░реВрд░рдд рдХреА рд╣рд░ рдЪреАрдЬ рд▓реЗрдВрдЧреЗ:


  • рдЧреЛ / рд╕реНрдХреИрдирд░ рдЖрдкрдХреЛ рдкрд╛рда рд╕реЗ рдЯреЛрдХрди рдХрд╛ рдПрдХ рд╕реЗрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ
  • go/token , scanner

, , :


type Token struct {
    kind  token.Token //  () , INT/IDENT/ADD
    value string      //   
}

scanner.Scanner lexer, :


  • Peek() тАФ ,
  • Consume() тАФ ,

go/ast, , .


Go right-associative , .


Go тАФ statement, expression. . , .


. , , .


. , README : github.com/richardjennings/prattparser.


, .


// exprNode     AST.
type exprNode interface {
    expr()
}

type nameExpr struct {
    Value string
}

type prefixExpr struct {
    Op  token.Token //  , , '+'  '-'
    Arg exprNode    //   
}

func (e *nameExpr) expr()   {}
func (e *prefixExpr) expr() {}

, parseExpr(), :


func (p *exprParser) parseExpr() exprNode {
    tok := p.lexer.Consume()
    switch tok.kind {
    case token.IDENT:
        return p.parseName(tok)
    case token.ADD, token.SUB:
        return p.parsePrefixExpr(tok)
    case token.LPAREN:
        return p.parseParenExpr(tok)
    // ...   
    }
}

func (p *exprParser) parseName(tok Token) exprNode {
    return &nameExpr{Value: tok.value}
}

func (p *exprParser) parsePrefixExpr(tok Token) exprNode {
    arg := p.parseExpr()
    return &prefixExpr{Op: tok.kind, Arg: arg}
}

- .


, . , -, parsePrefixExpr(), map , . , , map.


, prefixParselet:


type prefixParselet func(Token) exprNode

map[token.Token]prefixParselet. :


func newExprParser() *exprParser {
    p := &exprParser{
        prefixParselets: make(map[token.Token]prefixParselet),
    }

    prefixExpr := func(kinds ...token.Token) {
        for _, kind := range kinds {
            p.prefixParselets[kind] = p.parsePrefixExpr
        }
    }

    p.prefixParselets[token.IDENT] = p.parseName
    prefixExpr(token.ADD, token.SUB)

    return p
}

prefixExpr() . , (. ).


func (p *exprParser) parseExpr() exprNode {
  tok := p.lexer.consume()
  prefix, ok := p.prefixParselets[tok.kind]
  if !ok {
    // Parse error: unexpected token
  }
  return prefix(tok)
}


, x+y.


nameExpr{Value:"x"}, +. , .


infixParselet, prefixParselet , Expr, . x+y x.


type infixParselet func(left exprNode, tok Token) exprNode

map. , .


, + - binaryExpr:


func (p *exprParser) parseBinaryExpr(left exprNode, tok token) exprNode {
    right := p.parseExpr()
    return &binaryExpr{Op: tok.kind, Left: left, Right: right}
}

parseExpr() :


func (p *exprParser) parseExpr() exprNode {
    tok := p.lexer.Consume()
    prefix, ok := p.prefixParselets[tok.kind]
    if !ok {
        // Parse error: unexpected token
    }
    left := prefix(tok)
    tok = p.lexer.Peek()
    infix, ok := p.infixParselets[tok.kind]
    if !ok {
        return left
    }
    p.lexer.Consume() //  skip/discard  
    return infix(left, tok)
}

:


  1. -: x-y-z => x-(y-z)
  2. : x*y+z => x*(y+z)


, .


{token.Token => precedence}. , , :


p.prefixPrecedenceTab = map[token.Token]int{
    token.ADD: 4,
    token.SUB: 4,
}

p.infixPrecedenceTab = map[token.Token]int{
    token.ADD: 2,
    token.SUB: 2,
    token.MUL: 3,
    token.QUO: 3,
    // ...   
}

parseExpr() precedence:


func (p *exprParser) parseExpr(precedence int) exprNode {
    tok := p.lexer.Consume()
    prefix, ok := p.prefixParselets[tok.kind]
    if !ok {
        // Parse error: unexpected token
    }
    left := prefix(tok)

    for precedence < p.infixPrecedenceTab[p.lexer.Peek().kind] {
        tok := p.lexer.Consume()
        infix := p.infixParselets[tok.kind]
        left = infix(left, tok)
    }

    return left
}

, , , AST.


precedence () parseExpr():


func (p *exprParser) parseBinaryExpr(left exprNode, tok Token) exprNode {
    right := p.parseExpr(p.infixPrecedenceTab[tok.kind])
    return &binaryExpr{Op: tok.kind, Left: left, Right: right}
}

parseBinaryExpr() -. - , 1 :


func (p *exprParser) rparseBinaryExpr(left exprNode, tok Token) exprNode {
    right := p.parseExpr(p.infixPrecedenceTab[tok.kind] - 1)
    return &binaryExpr{Op: tok.kind, Left: left, Right: right}
}

, << -, rparseBinaryExpr().



тАФ infixParselet, '(' parseExpr(0) , ')'.


() тАФ prefixParselet, '(' parseExpr(0), ')'.


func (p *exprParser) parseParenExpr(tok Token) exprNode {
    x := p.parseExpr(0)
    p.expect(token.RPAREN)
    return x
}

тАФ infixParselet:


func (p *exprParser) parsePostfixExpr(left exprNode, tok Token) exprNode {
    return &postfixExpr{Op: tok.kind, Arg: left}
}


, , .


, , , helper- precedence:


prefixExpr := func(precedence int, kinds ...token.Token) {
    for _, kind := range kinds {
        p.prefixParselets[kind] = p.parsePrefixExpr
        p.prefixPrecedenceTab[kind] = precedence
    }
}

:


addPrefixParselet(token.LPAREN, 0, p.parseParenExpr)
addPrefixParselet(token.IDENT, 0, p.parseNameExpr)
leftAssocBinaryExpr(1, token.LOR)  // ||
leftAssocBinaryExpr(2, token.LAND) // &&
leftAssocBinaryExpr(3,
    token.EQL, // ==
    token.NEQ, // !=
)
rightAssocBinaryExpr(4,
    token.SHL, // <<
)
leftAssocBinaryExpr(4,
    token.ADD, // +
    token.SUB, // -
    token.SHR, // >>
)
leftAssocBinaryExpr(5,
    token.MUL, // *
    token.QUO, // /
    token.REM, // %
)
prefixExpr(6,
    token.ADD, // +
    token.SUB, // -
    token.INC, // ++
    token.DEC, // --
)
postfixExpr(7,
    token.INC, // ++
    token.DEC, // --
)
addInfixParselet(token.LPAREN, 8, p.parseCallExpr)

, , PrecAdd=3, PrecMult=4 .


map.


, , newExprParser . prefixParselet infixParslet , тАФ *exprParser.


, , . , : , тАФ .



Pratt Parsers: Expression Parsing Made Easy (Bob Nystrom). , , , , ", ".


, .


github.com/quasilyte/pratt-parsers-go.


: github.com/richardjennings/prattparser.




:



All Articles