This commit is contained in:
Marvin Blum
2015-09-21 22:00:01 +02:00
parent 1c02007ac3
commit 316bbd5e2f
6 changed files with 392 additions and 392 deletions

BIN
bin/main

Binary file not shown.

Binary file not shown.

View File

@@ -1,317 +1,317 @@
package asl package asl
import ( import (
"strconv" "strconv"
) )
const TAB = " " const TAB = " "
func Parse(token []Token) string { func Parse(token []Token) string {
initParser(token) initParser(token)
for tokenIndex < len(token) { for tokenIndex < len(token) {
parseBlock() parseBlock()
} }
return out return out
} }
func parseBlock() { func parseBlock() {
if accept("var") { if accept("var") {
parseVar() parseVar()
} else if accept("if") { } else if accept("if") {
parseIf() parseIf()
} else if accept("while") { } else if accept("while") {
parseWhile() parseWhile()
} else if accept("switch") { } else if accept("switch") {
parseSwitch() parseSwitch()
} else if accept("for") { } else if accept("for") {
parseFor() parseFor()
} else if accept("each") { } else if accept("each") {
parseForeach() parseForeach()
} else if accept("func") { } else if accept("func") {
parseFunction() parseFunction()
} else if accept("return") { } else if accept("return") {
parseReturn() parseReturn()
} else if accept("sqf") { } else if accept("sqf") {
parseSqf() parseSqf()
} else { } else {
parseStatement() parseStatement()
} }
if !end() && !accept("}") { if !end() && !accept("}") {
parseBlock() parseBlock()
} }
} }
func parseVar() { func parseVar() {
expect("var") expect("var")
appendOut(get().token) appendOut(get().token)
next() next()
if accept("=") { if accept("=") {
next() next()
appendOut(" = ") appendOut(" = ")
parseExpression(true) parseExpression(true)
} }
appendOut(";\n") appendOut(";\n")
expect(";") expect(";")
} }
func parseIf() { func parseIf() {
expect("if") expect("if")
appendOut("if (") appendOut("if (")
parseExpression(true) parseExpression(true)
appendOut(") then {\n") appendOut(") then {\n")
expect("{") expect("{")
parseBlock() parseBlock()
expect("}") expect("}")
if accept("else") { if accept("else") {
next() next()
expect("{") expect("{")
appendOut("} else {\n") appendOut("} else {\n")
parseBlock() parseBlock()
expect("}") expect("}")
} }
appendOut("};\n") appendOut("};\n")
} }
func parseWhile() { func parseWhile() {
expect("while") expect("while")
appendOut("while {") appendOut("while {")
parseExpression(true) parseExpression(true)
appendOut("} do {\n") appendOut("} do {\n")
expect("{") expect("{")
parseBlock() parseBlock()
expect("}") expect("}")
appendOut("};\n") appendOut("};\n")
} }
func parseSwitch() { func parseSwitch() {
expect("switch") expect("switch")
appendOut("switch (") appendOut("switch (")
parseExpression(true) parseExpression(true)
appendOut(") do {\n") appendOut(") do {\n")
expect("{") expect("{")
parseSwitchBlock() parseSwitchBlock()
expect("}") expect("}")
appendOut("};\n") appendOut("};\n")
} }
func parseSwitchBlock() { func parseSwitchBlock() {
if accept("}") { if accept("}") {
return return
} }
if accept("case") { if accept("case") {
expect("case") expect("case")
appendOut("case ") appendOut("case ")
parseExpression(true) parseExpression(true)
expect(":") expect(":")
appendOut(":\n") appendOut(":\n")
if !accept("case") && !accept("}") { if !accept("case") && !accept("}") {
appendOut("{\n") appendOut("{\n")
parseBlock() parseBlock()
appendOut("};\n") appendOut("};\n")
} }
} else if accept("default") { } else if accept("default") {
expect("default") expect("default")
expect(":") expect(":")
appendOut("default:\n") appendOut("default:\n")
if !accept("}") { if !accept("}") {
appendOut("{\n") appendOut("{\n")
parseBlock() parseBlock()
appendOut("};\n") appendOut("};\n")
} }
} }
parseSwitchBlock() parseSwitchBlock()
} }
func parseFor() { func parseFor() {
expect("for") expect("for")
appendOut("for [{") appendOut("for [{")
// var in first assignment is optional // var in first assignment is optional
if accept("var") { if accept("var") {
next() next()
} }
parseExpression(true) parseExpression(true)
expect(";") expect(";")
appendOut("}, {") appendOut("}, {")
parseExpression(true) parseExpression(true)
expect(";") expect(";")
appendOut("}, {") appendOut("}, {")
parseExpression(true) parseExpression(true)
expect(";") expect(";")
appendOut("}] do {\n") appendOut("}] do {\n")
expect("{") expect("{")
parseBlock() parseBlock()
expect("}") expect("}")
appendOut("};\n") appendOut("};\n")
} }
func parseForeach() { func parseForeach() {
expect("each") expect("each")
expr := parseExpression(false) expr := parseExpression(false)
expect("{") expect("{")
appendOut("{\n") appendOut("{\n")
parseBlock() parseBlock()
expect("}") expect("}")
appendOut("} forEach ("+expr+");\n") appendOut("} forEach (" + expr + ");\n")
} }
func parseFunction() { func parseFunction() {
expect("func") expect("func")
appendOut(get().token+" = {\n") appendOut(get().token + " = {\n")
next() next()
expect("(") expect("(")
parseFunctionParameter() parseFunctionParameter()
expect(")") expect(")")
expect("{") expect("{")
parseBlock() parseBlock()
expect("}") expect("}")
appendOut("};\n") appendOut("};\n")
} }
func parseFunctionParameter() { func parseFunctionParameter() {
// empty parameter list // empty parameter list
if accept("{") { if accept("{") {
return; return
} }
i := int64(0) i := int64(0)
for !accept(")") { for !accept(")") {
name := get().token name := get().token
next() next()
appendOut(name+" = _this select "+strconv.FormatInt(i, 10)+";\n") appendOut(name + " = _this select " + strconv.FormatInt(i, 10) + ";\n")
i++ i++
if !accept(")") { if !accept(")") {
expect(",") expect(",")
} }
} }
} }
func parseReturn() { func parseReturn() {
expect("return") expect("return")
appendOut("return ") appendOut("return ")
parseExpression(true) parseExpression(true)
expect(";") expect(";")
appendOut(";\n") appendOut(";\n")
} }
func parseSqf() { func parseSqf() {
expect("sqf") expect("sqf")
expect(":") expect(":")
for !accept("sqf") { for !accept("sqf") {
appendOut(get().token) appendOut(get().token)
next() next()
} }
appendOut("\n") appendOut("\n")
expect("sqf") expect("sqf")
} }
// Everything that does not start with a keyword. // Everything that does not start with a keyword.
func parseStatement() { func parseStatement() {
// empty block // empty block
if accept("}") || accept("case") || accept("default") { if accept("}") || accept("case") || accept("default") {
return return
} }
// variable or function name // variable or function name
name := get().token name := get().token
next() next()
if accept("=") { if accept("=") {
appendOut(name) appendOut(name)
parseAssignment() parseAssignment()
} else if name == "$" { } else if name == "$" {
name = get().token name = get().token
next() next()
parseBuildinFunctionCall(name); parseBuildinFunctionCall(name)
} else { } else {
parseFunctionCall() parseFunctionCall()
appendOut(name+";\n") appendOut(name + ";\n")
} }
if !end() { if !end() {
parseBlock() parseBlock()
} }
} }
func parseAssignment() { func parseAssignment() {
expect("=") expect("=")
appendOut(" = "+get().token) appendOut(" = " + get().token)
next() next()
expect(";") expect(";")
appendOut(";\n") appendOut(";\n")
} }
func parseFunctionCall() { func parseFunctionCall() {
expect("(") expect("(")
appendOut("[") appendOut("[")
parseParameter() parseParameter()
expect(")") expect(")")
expect(";") expect(";")
appendOut("] call ") appendOut("] call ")
} }
func parseBuildinFunctionCall(name string) { func parseBuildinFunctionCall(name string) {
expect("(") expect("(")
appendOut("[") appendOut("[")
parseParameter() parseParameter()
expect(")") expect(")")
appendOut("] ") appendOut("] ")
expect("(") expect("(")
appendOut(name+" [") appendOut(name + " [")
parseParameter() parseParameter()
expect(")") expect(")")
expect(";") expect(";")
appendOut("];\n") appendOut("];\n")
} }
func parseParameter() { func parseParameter() {
for !accept(")") { for !accept(")") {
parseExpression(true) parseExpression(true)
if !accept(")") { if !accept(")") {
expect(",") expect(",")
appendOut(", ") appendOut(", ")
} }
} }
} }
func parseExpression(out bool) string { func parseExpression(out bool) string {
openingBrackets := 0 openingBrackets := 0
output := "" output := ""
for !accept(",") && !accept(":") && !accept(";") && !accept("{") && !accept("}") && (openingBrackets != 0 || !accept(")")) { for !accept(",") && !accept(":") && !accept(";") && !accept("{") && !accept("}") && (openingBrackets != 0 || !accept(")")) {
current := get().token current := get().token
if out { if out {
appendOut(current) appendOut(current)
} else { } else {
output += current output += current
} }
if accept("(") { if accept("(") {
openingBrackets++ openingBrackets++
} else if accept(")") { } else if accept(")") {
openingBrackets-- openingBrackets--
} }
next() next()
} }
return output return output
} }

View File

@@ -6,48 +6,48 @@ var out string
var offset int var offset int
func initParser(token []Token) { func initParser(token []Token) {
if len(token) == 0 { if len(token) == 0 {
panic("No tokens provided") panic("No tokens provided")
} }
tokens = token tokens = token
tokenIndex = 0 tokenIndex = 0
out = "" out = ""
offset = 0 offset = 0
} }
func accept(token string) bool { func accept(token string) bool {
return tokenIndex < len(tokens) && tokenEqual(token, get()) return tokenIndex < len(tokens) && tokenEqual(token, get())
} }
func expect(token string) { func expect(token string) {
if !tokenEqual(token, get()) { if !tokenEqual(token, get()) {
panic("Parse error, expected '"+token+"' but was '"+get().token+"'") panic("Parse error, expected '" + token + "' but was '" + get().token + "'")
} }
next() next()
} }
func next() { func next() {
tokenIndex++ tokenIndex++
} }
func get() Token { func get() Token {
if tokenIndex >= len(tokens) { if tokenIndex >= len(tokens) {
panic("No more tokens") panic("No more tokens")
} }
return tokens[tokenIndex] return tokens[tokenIndex]
} }
func end() bool { func end() bool {
return tokenIndex == len(tokens) return tokenIndex == len(tokens)
} }
func tokenEqual(a string, b Token) bool { func tokenEqual(a string, b Token) bool {
return a == b.token return a == b.token
} }
func appendOut(str string) { func appendOut(str string) {
out += str out += str
} }

View File

@@ -1,140 +1,140 @@
package asl package asl
import ( import (
"strings" "fmt"
"fmt" "strings"
) )
type Token struct{ type Token struct {
token string token string
} }
var delimiter = []byte{ var delimiter = []byte{
'=', '=',
';', ';',
'{', '{',
'}', '}',
'(', '(',
')', ')',
'<', '<',
'>', '>',
'!', '!',
',', ',',
':', ':',
'&', '&',
'|', '|',
'$'} '$'}
var keywords = []string{ var keywords = []string{
"var", "var",
"if", "if",
"while", "while",
"switch", "switch",
"for", "for",
"each", "each",
"func", "func",
"true", "true",
"false", "false",
"case", "case",
"default", "default",
"return", "return",
"sqfstart", "sqfstart",
"sqf"} "sqf"}
var whitespace = []byte{' ', '\n', '\t'} var whitespace = []byte{' ', '\n', '\t'}
func Tokenize(code []byte) []Token { func Tokenize(code []byte) []Token {
code = removeComments(code) code = removeComments(code)
tokens := make([]Token, 0) tokens := make([]Token, 0)
token := "" token := ""
fmt.Println(string(code)) fmt.Println(string(code))
for i := range code { for i := range code {
c := code[i] c := code[i]
if byteArrayContains(delimiter, c) { if byteArrayContains(delimiter, c) {
if token != "" { if token != "" {
tokens = append(tokens, Token{token}) tokens = append(tokens, Token{token})
} }
tokens = append(tokens, Token{string(c)}) tokens = append(tokens, Token{string(c)})
token = "" token = ""
} else if stringArrayContains(keywords, strings.ToLower(token)) { } else if stringArrayContains(keywords, strings.ToLower(token)) {
tokens = append(tokens, Token{token}) tokens = append(tokens, Token{token})
token = "" token = ""
} else if !byteArrayContains(whitespace, c) { } else if !byteArrayContains(whitespace, c) {
token += string(c) token += string(c)
} }
} }
return tokens return tokens
} }
func removeComments(code []byte) []byte { func removeComments(code []byte) []byte {
newcode := make([]byte, len(code)) newcode := make([]byte, len(code))
j := 0 j := 0
for i := 0; i < len(code); i++ {
c := code[i]
if c == '/' && nextChar(code, i) == '/' {
i = skipSingleLineComment(code, i+1)
continue
} else if c == '/' && nextChar(code, i) == '*' {
i = skipMultiLineComment(code, i+1)
continue
}
newcode[j] = c for i := 0; i < len(code); i++ {
j++ c := code[i]
}
if c == '/' && nextChar(code, i) == '/' {
return newcode[:j] i = skipSingleLineComment(code, i+1)
continue
} else if c == '/' && nextChar(code, i) == '*' {
i = skipMultiLineComment(code, i+1)
continue
}
newcode[j] = c
j++
}
return newcode[:j]
} }
func nextChar(code []byte, i int) byte { func nextChar(code []byte, i int) byte {
i++ i++
if i < len(code) { if i < len(code) {
return code[i] return code[i]
} }
return '0' return '0'
} }
func skipSingleLineComment(code []byte, i int) int { func skipSingleLineComment(code []byte, i int) int {
for i < len(code) && code[i] != '\n' { for i < len(code) && code[i] != '\n' {
i++ i++
} }
return i return i
} }
func skipMultiLineComment(code []byte, i int) int { func skipMultiLineComment(code []byte, i int) int {
for i < len(code) && !(code[i] == '*' && nextChar(code, i) == '/') { for i < len(code) && !(code[i] == '*' && nextChar(code, i) == '/') {
i++ i++
} }
return i+1 return i + 1
} }
func byteArrayContains(haystack []byte, needle byte) bool { func byteArrayContains(haystack []byte, needle byte) bool {
for i := range haystack { for i := range haystack {
if haystack[i] == needle { if haystack[i] == needle {
return true; return true
} }
} }
return false return false
} }
func stringArrayContains(haystack []string, needle string) bool { func stringArrayContains(haystack []string, needle string) bool {
for i := range haystack { for i := range haystack {
if haystack[i] == needle { if haystack[i] == needle {
return true; return true
} }
} }
return false return false
} }

View File

@@ -1,16 +1,16 @@
package main package main
import ( import (
"io/ioutil" "asl"
"asl" "fmt"
"fmt" "io/ioutil"
) )
func main(){ func main() {
// read test file // read test file
code, _ := ioutil.ReadFile("in/simple.asl") code, _ := ioutil.ReadFile("in/simple.asl")
token := asl.Tokenize(code) token := asl.Tokenize(code)
out := asl.Parse(token) out := asl.Parse(token)
fmt.Println(out) fmt.Println(out)
} }