Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
142
Task/Truth-table/Go/truth-table.go
Normal file
142
Task/Truth-table/Go/truth-table.go
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
in := bufio.NewScanner(os.Stdin)
|
||||
for {
|
||||
fmt.Print("Expr: ")
|
||||
in.Scan()
|
||||
if err := in.Err(); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
if !tt(in.Text()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func tt(expr string) bool {
|
||||
// call library parser
|
||||
tree, err := parser.ParseExpr(expr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false
|
||||
}
|
||||
// create handy object to pass around
|
||||
e := &evaluator{nil, map[string]bool{}, tree}
|
||||
// library tree traversal function calls e.Visit for each node.
|
||||
// use this to collect variables of the expression.
|
||||
ast.Walk(e, tree)
|
||||
// print headings for truth table
|
||||
for _, n := range e.names {
|
||||
fmt.Printf("%-6s", n)
|
||||
}
|
||||
fmt.Println(" ", expr)
|
||||
// start recursive table generation function on first variable
|
||||
e.evalVar(0)
|
||||
return true
|
||||
}
|
||||
|
||||
type evaluator struct {
|
||||
names []string // variables, in order of appearance
|
||||
val map[string]bool // map variables to boolean values
|
||||
tree ast.Expr // parsed expression as ast
|
||||
}
|
||||
|
||||
// visitor function called by library Walk function.
|
||||
// builds a list of unique variable names.
|
||||
func (e *evaluator) Visit(n ast.Node) ast.Visitor {
|
||||
if id, ok := n.(*ast.Ident); ok {
|
||||
if !e.val[id.Name] {
|
||||
e.names = append(e.names, id.Name)
|
||||
e.val[id.Name] = true
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// method recurses for each variable of the truth table, assigning it to
|
||||
// false, then true. At bottom of recursion, when all variables are
|
||||
// assigned, it evaluates the expression and outputs one line of the
|
||||
// truth table
|
||||
func (e *evaluator) evalVar(nx int) bool {
|
||||
if nx == len(e.names) {
|
||||
// base case
|
||||
v, err := evalNode(e.tree, e.val)
|
||||
if err != nil {
|
||||
fmt.Println(" ", err)
|
||||
return false
|
||||
}
|
||||
// print variable values
|
||||
for _, n := range e.names {
|
||||
fmt.Printf("%-6t", e.val[n])
|
||||
}
|
||||
// print expression value
|
||||
fmt.Println(" ", v)
|
||||
return true
|
||||
}
|
||||
// recursive case
|
||||
for _, v := range []bool{false, true} {
|
||||
e.val[e.names[nx]] = v
|
||||
if !e.evalVar(nx + 1) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// recursively evaluate ast
|
||||
func evalNode(nd ast.Node, val map[string]bool) (bool, error) {
|
||||
switch n := nd.(type) {
|
||||
case *ast.Ident:
|
||||
return val[n.Name], nil
|
||||
case *ast.BinaryExpr:
|
||||
x, err := evalNode(n.X, val)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
y, err := evalNode(n.Y, val)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
switch n.Op {
|
||||
case token.AND:
|
||||
return x && y, nil
|
||||
case token.OR:
|
||||
return x || y, nil
|
||||
case token.XOR:
|
||||
return x != y, nil
|
||||
default:
|
||||
return unsup(n.Op)
|
||||
}
|
||||
case *ast.UnaryExpr:
|
||||
x, err := evalNode(n.X, val)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
switch n.Op {
|
||||
case token.XOR:
|
||||
return !x, nil
|
||||
default:
|
||||
return unsup(n.Op)
|
||||
}
|
||||
case *ast.ParenExpr:
|
||||
return evalNode(n.X, val)
|
||||
}
|
||||
return unsup(reflect.TypeOf(nd))
|
||||
}
|
||||
|
||||
func unsup(i interface{}) (bool, error) {
|
||||
return false, errors.New(fmt.Sprintf("%v unsupported", i))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue