Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
296
Task/Compiler-AST-interpreter/Go/compiler-ast-interpreter.go
Normal file
296
Task/Compiler-AST-interpreter/Go/compiler-ast-interpreter.go
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NodeType int
|
||||
|
||||
const (
|
||||
ndIdent NodeType = iota
|
||||
ndString
|
||||
ndInteger
|
||||
ndSequence
|
||||
ndIf
|
||||
ndPrtc
|
||||
ndPrts
|
||||
ndPrti
|
||||
ndWhile
|
||||
ndAssign
|
||||
ndNegate
|
||||
ndNot
|
||||
ndMul
|
||||
ndDiv
|
||||
ndMod
|
||||
ndAdd
|
||||
ndSub
|
||||
ndLss
|
||||
ndLeq
|
||||
ndGtr
|
||||
ndGeq
|
||||
ndEql
|
||||
ndNeq
|
||||
ndAnd
|
||||
ndOr
|
||||
)
|
||||
|
||||
type Tree struct {
|
||||
nodeType NodeType
|
||||
left *Tree
|
||||
right *Tree
|
||||
value int
|
||||
}
|
||||
|
||||
// dependency: Ordered by NodeType, must remain in same order as NodeType enum
|
||||
type atr struct {
|
||||
enumText string
|
||||
nodeType NodeType
|
||||
}
|
||||
|
||||
var atrs = []atr{
|
||||
{"Identifier", ndIdent},
|
||||
{"String", ndString},
|
||||
{"Integer", ndInteger},
|
||||
{"Sequence", ndSequence},
|
||||
{"If", ndIf},
|
||||
{"Prtc", ndPrtc},
|
||||
{"Prts", ndPrts},
|
||||
{"Prti", ndPrti},
|
||||
{"While", ndWhile},
|
||||
{"Assign", ndAssign},
|
||||
{"Negate", ndNegate},
|
||||
{"Not", ndNot},
|
||||
{"Multiply", ndMul},
|
||||
{"Divide", ndDiv},
|
||||
{"Mod", ndMod},
|
||||
{"Add", ndAdd},
|
||||
{"Subtract", ndSub},
|
||||
{"Less", ndLss},
|
||||
{"LessEqual", ndLeq},
|
||||
{"Greater", ndGtr},
|
||||
{"GreaterEqual", ndGeq},
|
||||
{"Equal", ndEql},
|
||||
{"NotEqual", ndNeq},
|
||||
{"And", ndAnd},
|
||||
{"Or", ndOr},
|
||||
}
|
||||
|
||||
var (
|
||||
stringPool []string
|
||||
globalNames []string
|
||||
globalValues = make(map[int]int)
|
||||
)
|
||||
|
||||
var (
|
||||
err error
|
||||
scanner *bufio.Scanner
|
||||
)
|
||||
|
||||
func reportError(msg string) {
|
||||
log.Fatalf("error : %s\n", msg)
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func btoi(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func itob(i int) bool {
|
||||
if i == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func makeNode(nodeType NodeType, left *Tree, right *Tree) *Tree {
|
||||
return &Tree{nodeType, left, right, 0}
|
||||
}
|
||||
|
||||
func makeLeaf(nodeType NodeType, value int) *Tree {
|
||||
return &Tree{nodeType, nil, nil, value}
|
||||
}
|
||||
|
||||
func interp(x *Tree) int { // interpret the parse tree
|
||||
if x == nil {
|
||||
return 0
|
||||
}
|
||||
switch x.nodeType {
|
||||
case ndInteger:
|
||||
return x.value
|
||||
case ndIdent:
|
||||
return globalValues[x.value]
|
||||
case ndString:
|
||||
return x.value
|
||||
case ndAssign:
|
||||
n := interp(x.right)
|
||||
globalValues[x.left.value] = n
|
||||
return n
|
||||
case ndAdd:
|
||||
return interp(x.left) + interp(x.right)
|
||||
case ndSub:
|
||||
return interp(x.left) - interp(x.right)
|
||||
case ndMul:
|
||||
return interp(x.left) * interp(x.right)
|
||||
case ndDiv:
|
||||
return interp(x.left) / interp(x.right)
|
||||
case ndMod:
|
||||
return interp(x.left) % interp(x.right)
|
||||
case ndLss:
|
||||
return btoi(interp(x.left) < interp(x.right))
|
||||
case ndGtr:
|
||||
return btoi(interp(x.left) > interp(x.right))
|
||||
case ndLeq:
|
||||
return btoi(interp(x.left) <= interp(x.right))
|
||||
case ndEql:
|
||||
return btoi(interp(x.left) == interp(x.right))
|
||||
case ndNeq:
|
||||
return btoi(interp(x.left) != interp(x.right))
|
||||
case ndAnd:
|
||||
return btoi(itob(interp(x.left)) && itob(interp(x.right)))
|
||||
case ndOr:
|
||||
return btoi(itob(interp(x.left)) || itob(interp(x.right)))
|
||||
case ndNegate:
|
||||
return -interp(x.left)
|
||||
case ndNot:
|
||||
if interp(x.left) == 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
case ndIf:
|
||||
if interp(x.left) != 0 {
|
||||
interp(x.right.left)
|
||||
} else {
|
||||
interp(x.right.right)
|
||||
}
|
||||
return 0
|
||||
case ndWhile:
|
||||
for interp(x.left) != 0 {
|
||||
interp(x.right)
|
||||
}
|
||||
return 0
|
||||
case ndPrtc:
|
||||
fmt.Printf("%c", interp(x.left))
|
||||
return 0
|
||||
case ndPrti:
|
||||
fmt.Printf("%d", interp(x.left))
|
||||
return 0
|
||||
case ndPrts:
|
||||
fmt.Print(stringPool[interp(x.left)])
|
||||
return 0
|
||||
case ndSequence:
|
||||
interp(x.left)
|
||||
interp(x.right)
|
||||
return 0
|
||||
default:
|
||||
reportError(fmt.Sprintf("interp: unknown tree type %d\n", x.nodeType))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func getEnumValue(name string) NodeType {
|
||||
for _, atr := range atrs {
|
||||
if atr.enumText == name {
|
||||
return atr.nodeType
|
||||
}
|
||||
}
|
||||
reportError(fmt.Sprintf("Unknown token %s\n", name))
|
||||
return -1
|
||||
}
|
||||
|
||||
func fetchStringOffset(s string) int {
|
||||
var d strings.Builder
|
||||
s = s[1 : len(s)-1]
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == '\\' && (i+1) < len(s) {
|
||||
if s[i+1] == 'n' {
|
||||
d.WriteByte('\n')
|
||||
i++
|
||||
} else if s[i+1] == '\\' {
|
||||
d.WriteByte('\\')
|
||||
i++
|
||||
}
|
||||
} else {
|
||||
d.WriteByte(s[i])
|
||||
}
|
||||
}
|
||||
s = d.String()
|
||||
for i := 0; i < len(stringPool); i++ {
|
||||
if s == stringPool[i] {
|
||||
return i
|
||||
}
|
||||
}
|
||||
stringPool = append(stringPool, s)
|
||||
return len(stringPool) - 1
|
||||
}
|
||||
|
||||
func fetchVarOffset(name string) int {
|
||||
for i := 0; i < len(globalNames); i++ {
|
||||
if globalNames[i] == name {
|
||||
return i
|
||||
}
|
||||
}
|
||||
globalNames = append(globalNames, name)
|
||||
return len(globalNames) - 1
|
||||
}
|
||||
|
||||
func loadAst() *Tree {
|
||||
var nodeType NodeType
|
||||
var s string
|
||||
if scanner.Scan() {
|
||||
line := strings.TrimRight(scanner.Text(), " \t")
|
||||
tokens := strings.Fields(line)
|
||||
first := tokens[0]
|
||||
if first[0] == ';' {
|
||||
return nil
|
||||
}
|
||||
nodeType = getEnumValue(first)
|
||||
le := len(tokens)
|
||||
if le == 2 {
|
||||
s = tokens[1]
|
||||
} else if le > 2 {
|
||||
idx := strings.Index(line, `"`)
|
||||
s = line[idx:]
|
||||
}
|
||||
}
|
||||
check(scanner.Err())
|
||||
if s != "" {
|
||||
var n int
|
||||
switch nodeType {
|
||||
case ndIdent:
|
||||
n = fetchVarOffset(s)
|
||||
case ndInteger:
|
||||
n, err = strconv.Atoi(s)
|
||||
check(err)
|
||||
case ndString:
|
||||
n = fetchStringOffset(s)
|
||||
default:
|
||||
reportError(fmt.Sprintf("Unknown node type: %s\n", s))
|
||||
}
|
||||
return makeLeaf(nodeType, n)
|
||||
}
|
||||
left := loadAst()
|
||||
right := loadAst()
|
||||
return makeNode(nodeType, left, right)
|
||||
}
|
||||
|
||||
func main() {
|
||||
ast, err := os.Open("ast.txt")
|
||||
check(err)
|
||||
defer ast.Close()
|
||||
scanner = bufio.NewScanner(ast)
|
||||
x := loadAst()
|
||||
interp(x)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue