Skip to content

Commit

Permalink
Merge pull request #1 from elliotchance/master
Browse files Browse the repository at this point in the history
Update
  • Loading branch information
zoeyfyi authored Apr 16, 2017
2 parents f459456 + 6040490 commit 336ffbb
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 51 deletions.
8 changes: 5 additions & 3 deletions ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,18 @@ func Parse(line string) interface{} {
node = parseVarDecl(line)
case "WhileStmt":
node = parseWhileStmt(line)
case "NullStmt":
node = nil
default:
panic("'" + line + "'")
panic("Unknown node type: '" + line + "'")
}

return node
}

func groupsFromRegex(rx, line string) map[string]string {
// We remove tabs and newlines from the regex. This is purely cosmetic
// as the regex input can be quite lone and its nice for the caller to
// We remove tabs and newlines from the regex. This is purely cosmetic,
// as the regex input can be quite long and it's nice for the caller to
// be able to format it in a more readable way.
fullRegexp := "(?P<address>[0-9a-fx]+) " +
strings.Replace(strings.Replace(rx, "\n", "", -1), "\t", "", -1)
Expand Down
18 changes: 18 additions & 0 deletions ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,24 @@ var nodes = map[string]interface{}{
Referenced: true,
Children: []interface{}{},
},
`0x7f9bc9083d00 <line:91:5, line:97:8> line:91:5 'unsigned short'`: &FieldDecl{
Address: "0x7f9bc9083d00",
Position: "line:91:5, line:97:8",
Position2: "line:91:5",
Name: "",
Type: "unsigned short",
Referenced: false,
Children: []interface{}{},
},
`0x30363a0 <col:18, col:29> __val 'int [2]'`: &FieldDecl{
Address: "0x30363a0",
Position: "col:18, col:29",
Position2: "",
Name: "__val",
Type: "int [2]",
Referenced: false,
Children: []interface{}{},
},

// FloatingLiteral
`0x7febe106f5e8 <col:24> 'double' 1.230000e+00`: &FloatingLiteral{
Expand Down
4 changes: 4 additions & 0 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ func printLine(out *bytes.Buffer, line string, indent int) {
}

func renderExpression(node interface{}) []string {
if node == nil {
return []string{"", "unknown54"}
}

if n, ok := node.(ExpressionRenderer); ok {
return n.Render()
}
Expand Down
4 changes: 2 additions & 2 deletions darwin/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ type _RuneLocale struct {
}

var _DefaultRuneLocale _RuneLocale = _RuneLocale{
__runetype: [256]uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, },
__runetype: [256]uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255},
}

func __maskrune(_c C__darwin_ct_rune_t, _f uint32) uint32 {
return _DefaultRuneLocale.__runetype[_c & 0xff] & _f;
return _DefaultRuneLocale.__runetype[_c&0xff] & _f
}

func __tolower(c C__darwin_ct_rune_t) C__darwin_ct_rune_t {
Expand Down
16 changes: 12 additions & 4 deletions field_decl.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ type FieldDecl struct {
func parseFieldDecl(line string) *FieldDecl {
groups := groupsFromRegex(
`<(?P<position>.*)>
(?P<position2> [^ ]+)?
(?P<position2> col:\d+| line:\d+:\d+)?
(?P<referenced> referenced)?
(?P<name>\w+?)
(?P<name> \w+?)?
'(?P<type>.+?)'`,
line,
)
Expand All @@ -29,7 +29,7 @@ func parseFieldDecl(line string) *FieldDecl {
Address: groups["address"],
Position: groups["position"],
Position2: strings.TrimSpace(groups["position2"]),
Name: groups["name"],
Name: strings.TrimSpace(groups["name"]),
Type: groups["type"],
Referenced: len(groups["referenced"]) > 0,
Children: []interface{}{},
Expand All @@ -38,19 +38,27 @@ func parseFieldDecl(line string) *FieldDecl {

func (n *FieldDecl) Render() []string {
fieldType := resolveType(n.Type)
name := strings.Replace(n.Name, "used", "", -1)
name := n.Name

//if name == "" {
// return []string{"", "unknown71"}
//}

// Go does not allow the name of a variable to be called "type". For the
// moment I will rename this to avoid the error.
if name == "type" {
name = "type_"
}

// It may have a default value.
suffix := ""
if len(n.Children) > 0 {
suffix = fmt.Sprintf(" = %s", renderExpression(n.Children[0])[0])
}

// NULL is a macro that one rendered looks like "(0)" we have to be
// sensitive to catch this as Go would complain that 0 (int) is not
// compatible with the type we are setting it to.
if suffix == " = (0)" {
suffix = " = nil"
}
Expand Down
39 changes: 34 additions & 5 deletions for_stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,42 @@ func parseForStmt(line string) *ForStmt {
func (n *ForStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) {
children := n.Children

a := renderExpression(children[0])[0]
b := renderExpression(children[1])[0]
c := renderExpression(children[2])[0]
// There are always 5 children in a ForStmt, for example:
//
// for ( c = 0 ; c < n ; c++ ) {
// doSomething();
// }
//
// 1. initExpression = BinaryStmt: c = 0
// 2. Not sure what this is for, but it's always nil. There is a panic
// below in case we discover what it is used for (pun intended).
// 3. conditionalExpression = BinaryStmt: c < n
// 4. stepExpression = BinaryStmt: c++
// 5. body = CompoundStmt: { CallExpr }

printLine(out, fmt.Sprintf("for %s; %s; %s {", a, b, c), indent)
if len(children) != 5 {
panic(fmt.Sprintf("Expected 5 children in ForStmt, got %#v", children))
}

// TODO: The second child of a ForStmt appears to always be null.
// Are there any cases where it is used?
if children[1] != nil {
panic("non-nil child 1 in ForStmt")
}

init := renderExpression(children[0])[0]
conditional := renderExpression(children[2])[0]
step := renderExpression(children[3])[0]
body := children[4]

if init == "" && conditional == "" && step == "" {
printLine(out, "for {", indent)
} else {
printLine(out, fmt.Sprintf("for %s; %s; %s {",
init, conditional, step), indent)
}

Render(out, children[3], functionName, indent+1, returnType)
Render(out, body, functionName, indent+1, returnType)

printLine(out, "}", indent)
}
51 changes: 46 additions & 5 deletions if_stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,55 @@ func parseIfStmt(line string) *IfStmt {
func (n *IfStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) {
children := n.Children

e := renderExpression(children[0])
printLine(out, fmt.Sprintf("if %s {", cast(e[0], e[1], "bool")), indent)
// There is always 4 or 5 children in an IfStmt. For example:
//
// if (i == 0) {
// return 0;
// } else {
// return 1;
// }
//
// 1. Not sure what this is for. This gets removed.
// 2. Not sure what this is for.
// 3. conditional = BinaryOperator: i == 0
// 4. body = CompoundStmt: { return 0; }
// 5. elseBody = CompoundStmt: { return 1; }
//
// elseBody will be nil if there is no else clause.

Render(out, children[1], functionName, indent+1, returnType)
// On linux I have seen only 4 children for an IfStmt with the same
// definitions above, but missing the first argument. Since we don't
// know what the first argument is for anyway we will just remove it on
// Mac if necessary.
if len(children) == 5 && children[0] != nil {
panic("non-nil child 0 in ForStmt")
}
if len(children) == 5 {
children = children[1:]
}

// From here on there must be 4 children.
if len(children) != 4 {
panic(fmt.Sprintf("Expected 4 children in IfStmt, got %#v", children))
}

// Maybe we will discover what the nil value is?
if children[0] != nil {
panic("non-nil child 0 in ForStmt")
}

conditional := renderExpression(children[1])

// The condition in Go must always be a bool.
boolCondition := cast(conditional[0], conditional[1], "bool")

printLine(out, fmt.Sprintf("if %s {", boolCondition), indent)

Render(out, children[2], functionName, indent+1, returnType)

if len(children) > 2 {
if children[3] != nil {
printLine(out, "} else {", indent)
Render(out, children[2], functionName, indent+1, returnType)
Render(out, children[3], functionName, indent+1, returnType)
}

printLine(out, "}", indent)
Expand Down
37 changes: 29 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
Expand All @@ -11,6 +12,10 @@ import (
"strings"
)

var (
printAst = flag.Bool("print-ast", false, "Print AST before translated Go code.")
)

func readAST(data []byte) []string {
uncolored := regexp.MustCompile(`\x1b\[[\d;]+m`).ReplaceAll(data, []byte{})
return strings.Split(string(uncolored), "\n")
Expand All @@ -23,15 +28,14 @@ func convertLinesToNodes(lines []string) []interface{} {
continue
}

// This will need to be handled more gracefully... I'm not even
// sure what this means?
if strings.Index(line, "<<<NULL>>>") >= 0 {
continue
}
// It is tempting to discard null AST nodes, but these may
// have semantic importance: for example, they represent omitted
// for-loop conditions, as in for(;;).
line = strings.Replace(line, "<<<NULL>>>", "NullStmt", 1)

indentAndType := regexp.MustCompile("^([|\\- `]*)(\\w+)").FindStringSubmatch(line)
if len(indentAndType) == 0 {
panic(fmt.Sprintf("Can not understand line '%s'", line))
panic(fmt.Sprintf("Cannot understand line '%s'", line))
}

offset := len(indentAndType[1])
Expand Down Expand Up @@ -125,7 +129,7 @@ func Start(args []string) string {
}

// 1. Compile it first (checking for errors)
cFilePath := args[1]
cFilePath := args[0]

// 2. Preprocess
pp, err := exec.Command("clang", "-E", cFilePath).Output()
Expand All @@ -140,6 +144,12 @@ func Start(args []string) string {
Check(err)

lines := readAST(ast_pp)
if *printAst {
for _, l := range lines {
fmt.Println(l)
}
fmt.Println()
}
nodes := convertLinesToNodes(lines)
tree := buildTree(nodes, 0)

Expand Down Expand Up @@ -168,5 +178,16 @@ func Start(args []string) string {
}

func main() {
fmt.Print(Start(os.Args))
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s <file.c>\n", os.Args[0])
flag.PrintDefaults()
}
flag.Parse()

if flag.NArg() < 1 {
flag.Usage()
os.Exit(1)
}

fmt.Print(Start(flag.Args()))
}
2 changes: 1 addition & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ func TestIntegrationScripts(t *testing.T) {
}

for _, file := range files {
Start([]string{"", file})
Start([]string{file})
}
}
42 changes: 21 additions & 21 deletions noarch/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,41 @@ package noarch
type __builtin_va_list int64

func BoolToInt(x bool) int {
if x {
return 1
}
if x {
return 1
}

return 0
return 0
}

func __bool_to_uint32(x bool) int {
if x {
return 1
}
if x {
return 1
}

return 0
return 0
}

func __not_uint32(x uint32) uint32 {
if x == 0 {
return 1
}
if x == 0 {
return 1
}

return 0
return 0
}

func NotInt(x int) int {
if x == 0 {
return 1
}
if x == 0 {
return 1
}

return 0
return 0
}

func Ternary(a bool, b, c func () interface{}) interface{} {
if a {
return b()
}
func Ternary(a bool, b, c func() interface{}) interface{} {
if a {
return b()
}

return c()
return c()
}
Loading

0 comments on commit 336ffbb

Please sign in to comment.