# Recursive downward algorithm to realize calculator

Time：2021-4-23

Using recursive downward algorithm combined with our`BKLexer`Implementation of support for four operations and bracket priority calculator program.

Code list [golang]

``````package main

import (
"fmt"
"os"
"bufio"
"strings"
"strconv"
"./bklexer"
)

type Node interface {
GetValue() float64
}

type Number struct {
value float64
}

func NewNumber(token *BKLexer.Token) *Number {
value, _ := strconv.ParseFloat(token.Source, 64)
return &Number{value: value}
}

func (number *Number) GetValue() float64 {
return number.value
}

type BinaryOpt struct {
opt string
lhs Node
rhs Node
}

func NewBinaryOpt(token *BKLexer.Token, lhs Node, rhs Node) *BinaryOpt {
return &BinaryOpt{opt: token.Source, lhs: lhs, rhs: rhs}
}

func (binaryOpt *BinaryOpt) GetValue() float64 {
lhs, rhs := binaryOpt.lhs, binaryOpt.rhs
switch binaryOpt.opt {
case "+": return lhs.GetValue() + rhs.GetValue()
case "-": return lhs.GetValue() - rhs.GetValue()
case "*": return lhs.GetValue() * rhs.GetValue()
case "/": return lhs.GetValue() / rhs.GetValue()
}
return 0
}

func parse(lexer *BKLexer.Lexer) Node {
token := lexer.GetToken()
if token.TType != BKLexer.TOKEN_TYPE_EOF {
return nil
}
return result
}

lhs := parse_binary_mul(lexer)
if lhs == nil {
return nil
}
token := lexer.GetToken()
for token.Source == "+" || token.Source == "-" {
rhs := parse_binary_mul(lexer)
if rhs == nil {
return nil
}
lhs = NewBinaryOpt(token, lhs, rhs)
token = lexer.GetToken()
}
return lhs
}

func parse_binary_mul(lexer *BKLexer.Lexer) Node {
lhs := parse_number(lexer)
if lhs == nil {
return nil
}
token := lexer.GetToken()
for token.Source == "*" || token.Source == "/" {
rhs := parse_number(lexer)
if rhs == nil {
return nil
}
lhs = NewBinaryOpt(token, lhs, rhs)
token = lexer.GetToken()
}
return lhs
}

func parse_number(lexer *BKLexer.Lexer) Node {
token := lexer.NextToken()
if token.Name == "LPAR" {
if expr == nil {
return nil
}
token := lexer.GetToken()
if token.Name != "RPAR" {
return nil
}
lexer.NextToken()
return expr
}
if token.Name == "NUMBER" {
number := NewNumber(token)
lexer.NextToken()
return number
}
return nil
}

func main() {
fmt.Println("Hello My Calc.")

lexer := BKLexer.NewLexer()

for true {
fmt.Print("> ")
inputs = strings.Trim(inputs, " \f\t\n")
if inputs == "quit" {
break
}
if inputs != "" {
lexer.Build(inputs)
result := parse(lexer)
if result == nil {
positon := lexer.GetToken().Col
fmt.Println("error in :", positon)
continue
}
fmt.Println("out =", result.GetValue())
}

}

fmt.Println("bye!")
}``````

#### Run the test

``````➜ go calc.go

Hello My Calc.
> 1 + (2 - 3) * 4 / 5
out = 0.19999999999999996
> quit
bye!``````

#### Bring in the package you need

``````import (
"fmt"
"os"
"bufio"
"strings"
"strconv"
"./bklexer"
)``````
• FMT printout
• OS + bufio read user input
• Strings handles strings
• Strconv parsing string
• Bklexer for lexical analysis

#### Define interface

``````type Node interface {
GetValue() float64
}``````

`Node`As an interface, it is used to point to other structures`GetValue`Method can get the value of the node.

#### Defining digital nodes

``````type Number struct {
value float64
}

func NewNumber(token *BKLexer.Token) *Number {
value, _ := strconv.ParseFloat(token.Source, 64)
return &Number{value: value}
}``````

`Number`As a node of numeric type, there are members`value`For storing values, use`NewNumber`Function can instantiate it.

#### Interface method of realizing digital node

``````func (number *Number) GetValue() float64 {
return number.value
}``````

#### Define operation node

``````type BinaryOpt struct {
opt string
lhs Node
rhs Node
}

func NewBinaryOpt(token *BKLexer.Token, lhs Node, rhs Node) *BinaryOpt {
return &BinaryOpt{opt: token.Source, lhs: lhs, rhs: rhs}
}``````

`BinaryOpt`As an operation node, members`opt`Record the operation symbol,`lhs``rhs`They are the contents on the left and right sides of the expression, such as 1 and 2 in 1 + 2.
use`NewBinaryOpt`Function instance.

#### Interface method to realize operation node

``````func (binaryOpt *BinaryOpt) GetValue() float64 {
lhs, rhs := binaryOpt.lhs, binaryOpt.rhs
switch binaryOpt.opt {
case "+": return lhs.GetValue() + rhs.GetValue()
case "-": return lhs.GetValue() - rhs.GetValue()
case "*": return lhs.GetValue() * rhs.GetValue()
case "/": return lhs.GetValue() / rhs.GetValue()
}
return 0
}``````

We need to operate symbols according to operations`opt`judge`lhs`And`rhs`How to calculate the value of.

#### Defines the entry function for syntax parsing

``````func parse(lexer *BKLexer.Lexer) Node {
token := lexer.GetToken()
if token.TType != BKLexer.TOKEN_TYPE_EOF {
return nil
}
return result
}``````

Entry function`parse`Received`*BKLexer.Lexer`Type, it is sent to the`parse_binary_add`In the middle,
Try to resolve an operation with the same level of operation as the addition operation.
Finally, judge the current situation`token`Whether it is the end. If not, it returns`nil`Otherwise, the parsing result is returned.

#### Analytic functions that define addition level operations

``````func parse_binary_add(lexer *BKLexer.Lexer) Node {
lhs := parse_binary_mul(lexer)
if lhs == nil {
return nil
}
token := lexer.GetToken()
for token.Source == "+" || token.Source == "-" {
rhs := parse_binary_mul(lexer)
if rhs == nil {
return nil
}
lhs = NewBinaryOpt(token, lhs, rhs)
token = lexer.GetToken()
}
return lhs
}``````

When the function receives an argument`lexer`And the runtime will try to resolve the multiplication level operation first,
If the parsing is completed and returned successfully, the current`token`The literal quantity of determines whether the addition level operation node needs to be constructed,
If necessary, try to perform another multiplication level operation parsing. If the parsing is successful, it is based on the`opt`Constructs the node object of the current operation level.

#### Analytic functions that define multiplication level operations

``````func parse_binary_mul(lexer *BKLexer.Lexer) Node {
lhs := parse_number(lexer)
if lhs == nil {
return nil
}
token := lexer.GetToken()
for token.Source == "*" || token.Source == "/" {
rhs := parse_number(lexer)
if rhs == nil {
return nil
}
lhs = NewBinaryOpt(token, lhs, rhs)
token = lexer.GetToken()
}
return lhs
}``````

`parse_binary_mul`Basic and`parse_binary_add`It’s the same, except that at the beginning of the run, you try to parse the contents of a number or bracket expression,
When judging the need to build a multiplication level operation node, it is also an attempt to parse the content of another number or bracket expression.

#### Analytic functions that define numeric and bracket expressions

``````func parse_number(lexer *BKLexer.Lexer) Node {
token := lexer.NextToken()
if token.Name == "LPAR" {
if expr == nil {
return nil
}
token := lexer.GetToken()
if token.Name != "RPAR" {
return nil
}
lexer.NextToken()
return expr
}
if token.Name == "NUMBER" {
number := NewNumber(token)
lexer.NextToken()
return number
}
return nil
}``````

Get the next one first`token`To determine whether it is a left bracket. If it is, it may be a bracket expression, and you need to try to parse it,
If the parsing is successful, it is necessary to judge whether the end is a right bracket. If all the parsing are successful, the parsed expression node will be returned. Otherwise, it will be returned`nil`
If at the beginning`token`If it is not a left bracket but a number, a number node is instantiated and returned.
Returns if it is neither a left bracket nor a number`nil`

#### Define lexical analyzer rules

``````lexer := BKLexer.NewLexer()

#### Loop read user input and analyze calculation

``````reader := bufio.NewReader(os.Stdin)
for true {
fmt.Print("> ")
inputs = strings.Trim(inputs, " \f\t\n")
if inputs == "quit" {
break
}
if inputs != "" {
lexer.Build(inputs)
result := parse(lexer)
if result == nil {
positon := lexer.GetToken().Col
fmt.Println("error in :", positon)
continue
}
fmt.Println("out =", result.GetValue())
}
}
fmt.Println("bye!")``````

When analytic function`parse`The returned content is not`nil`Can be used when`GetValue`Function to evaluate the expression and get the result.

Part twoMake calculator support statement blockWelcome to the official account of the public housing number 100 Xiao Tong inn.

## Libp2p RS version 0.3.0 introduction

V0.3.0 released on 4.23, usingAsyncRead & AsyncWriteTo replace ourReadEx & WriteEx & SplitEx； SimplifiedKad/DHTImplementation logic. modify ReadEx & WriteEx & SplitEx: At first we tried to useasync-traitTo define their own IO operationsTraitFor more pure useasync/awaitTo write code. withReadExFor example, it is roughly as follows: #[async_trait] pub trait ReadEx { async fn read(&mut self, buf: &mut […]