Compiler/AST interpreter: Difference between revisions

Added Go
(→‎{{header|C}}: Added missing nd_Or case to switch statement in interp() function.)
(Added Go)
Line 1,367:
</lang>
Passes all tests.
 
=={{header|Go}}==
{{trans|C}}
<lang go>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)
}</lang>
 
{{out}}
<pre>
3 is prime
5 is prime
7 is prime
11 is prime
13 is prime
17 is prime
19 is prime
23 is prime
29 is prime
31 is prime
37 is prime
41 is prime
43 is prime
47 is prime
53 is prime
59 is prime
61 is prime
67 is prime
71 is prime
73 is prime
79 is prime
83 is prime
89 is prime
97 is prime
101 is prime
Total primes found: 26
</pre>
 
=={{header|Julia}}==
Line 1,564 ⟶ 1,893:
Total primes found: 26
</pre>
 
 
=={{header|Perl}}==
9,476

edits