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

View File

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

View File

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

View File

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