Repository: Konstantin8105/c4go
Pull request #459 (2019-06-14 21:31:21)

clang 8


Patch:
diff --git a/.travis.yml b/.travis.yml
index 63c9e00..5243eec 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -45,6 +45,8 @@ matrix:
 ####################################################
     - env: SCRIPT=test CLANG=7
       os: linux
+    - env: SCRIPT=test CLANG=8
+      os: linux
 ####### lint checking ########
     - env: SCRIPT=lint CLANG=3.9
       os: linux
diff --git a/ast/array_filler.go b/ast/array_filler.go
index 44ae605..4adaa5e 100644
--- a/ast/array_filler.go
+++ b/ast/array_filler.go
@@ -1,14 +1,42 @@
 package ast
 
+import (
+	"strings"
+)
+
 // ArrayFiller is type of array filler
 type ArrayFiller struct {
 	ChildNodes []Node
 }
 
+var arrayFillerMarkers = []string{
+	"array filler",
+	"array_filler",
+}
+
 func parseArrayFiller(line string) *ArrayFiller {
-	return &ArrayFiller{
+	arrfill := &ArrayFiller{
 		ChildNodes: []Node{},
 	}
+
+	for _, af := range arrayFillerMarkers {
+		if strings.HasPrefix(line, af+":") {
+			line = line[len(af+":")+1:]
+		}
+		if strings.HasPrefix(line, af) {
+			line = line[len(af):]
+		}
+	}
+	line = strings.TrimSpace(line)
+	if line != "" {
+		rn, err := Parse(line)
+		if err != nil {
+			panic(err)
+		}
+		arrfill.AddChild(rn)
+	}
+
+	return arrfill
 }
 
 // AddChild adds a new child node. Child nodes can then be accessed with the
diff --git a/ast/ast.go b/ast/ast.go
index 44c6c4b..6866b8b 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -47,8 +47,10 @@ func Parse(fullline string) (returnNode Node, err error) {
 
 	// This is a special case. I'm not sure if it's a bug in the clang AST
 	// dumper. It should have children.
-	if line == "array filler" {
-		return parseArrayFiller(line), nil
+	for _, af := range arrayFillerMarkers {
+		if strings.HasPrefix(line, af) {
+			return parseArrayFiller(line), nil
+		}
 	}
 
 	parts := strings.SplitN(line, " ", 2)
@@ -104,6 +106,8 @@ func Parse(fullline string) (returnNode Node, err error) {
 		return parseConditionalOperator(line), nil
 	case "ConstAttr":
 		return parseConstAttr(line), nil
+	case "ConstantExpr":
+		return parseConstantExpr(line), nil
 	case "ConstantArrayType":
 		return parseConstantArrayType(line), nil
 	case "ContinueStmt":
diff --git a/ast/constant_expr.go b/ast/constant_expr.go
new file mode 100644
index 0000000..9a533ae
--- /dev/null
+++ b/ast/constant_expr.go
@@ -0,0 +1,49 @@
+package ast
+
+// ConstantExpr is node constructor.
+type ConstantExpr struct {
+	Addr       Address
+	Pos        Position
+	Position2  string
+	Type       string
+	ChildNodes []Node
+}
+
+func parseConstantExpr(line string) *ConstantExpr {
+	groups := groupsFromRegex(
+		`<(?P<position>.*)> 
+		'(?P<type>.*?)'
+		`,
+		line,
+	)
+
+	return &ConstantExpr{
+		Addr:       ParseAddress(groups["address"]),
+		Pos:        NewPositionFromString(groups["position"]),
+		Type:       groups["type"],
+		ChildNodes: []Node{},
+	}
+}
+
+// AddChild adds a new child node. Child nodes can then be accessed with the
+// Children attribute.
+func (n *ConstantExpr) AddChild(node Node) {
+	n.ChildNodes = append(n.ChildNodes, node)
+}
+
+// Address returns the numeric address of the node. See the documentation for
+// the Address type for more information.
+func (n *ConstantExpr) Address() Address {
+	return n.Addr
+}
+
+// Children returns the child nodes. If this node does not have any children or
+// this node does not support children it will always return an empty slice.
+func (n *ConstantExpr) Children() []Node {
+	return n.ChildNodes
+}
+
+// Position returns the position in the original source code.
+func (n *ConstantExpr) Position() Position {
+	return n.Pos
+}
diff --git a/ast/if_stmt.go b/ast/if_stmt.go
index 38f2120..b11bb43 100644
--- a/ast/if_stmt.go
+++ b/ast/if_stmt.go
@@ -4,18 +4,20 @@ package ast
 type IfStmt struct {
 	Addr       Address
 	Pos        Position
+	HasElse    bool
 	ChildNodes []Node
 }
 
 func parseIfStmt(line string) *IfStmt {
 	groups := groupsFromRegex(
-		"<(?P<position>.*)>",
+		"<(?P<position>.*)>(?P<hasElse> has_else)?",
 		line,
 	)
 
 	return &IfStmt{
 		Addr:       ParseAddress(groups["address"]),
 		Pos:        NewPositionFromString(groups["position"]),
+		HasElse:    len(groups["hasElse"]) > 0,
 		ChildNodes: []Node{},
 	}
 }
diff --git a/ast/position.go b/ast/position.go
index b429f79..16ae010 100644
--- a/ast/position.go
+++ b/ast/position.go
@@ -270,6 +270,8 @@ func setPosition(node Node, position Position) {
 		n.Pos = position
 	case *ConstAttr:
 		n.Pos = position
+	case *ConstantExpr:
+		n.Pos = position
 	case *ContinueStmt:
 		n.Pos = position
 	case *CompoundAssignOperator:
diff --git a/noarch/stdio.go b/noarch/stdio.go
index b2473c9..8015364 100644
--- a/noarch/stdio.go
+++ b/noarch/stdio.go
@@ -1,11 +1,13 @@
 package noarch
 
 import (
+	"bytes"
 	"fmt"
 	"io"
 	"io/ioutil"
 	"os"
 	"reflect"
+	"strings"
 )
 
 // Programs generated by c4go will reference noarch.Stdin instead of os.Stdin
@@ -406,13 +408,16 @@ func Fprintf(f *File, format []byte, args ...interface{}) int32 {
 // string.
 func Fscanf(f *File, format []byte, args ...interface{}) int32 {
 	realArgs := prepareArgsForScanf(args)
+	goFormat := CStringToString(format)
+	iter := 0
+again:
 
-	// format is ignored
-	// See https://github.com/Konstantin8105/c4go/issues/607
-	_ = format
-
-	n, err := fmt.Fscan(f.OsFile, realArgs...)
+	n, err := fmt.Fscanf(f.OsFile, goFormat, realArgs...)
 	if err != nil {
+		if strings.Contains(err.Error(), "unexpected newline") && iter < 100 {
+			iter++
+			goto again
+		}
 		return -1
 	}
 
@@ -426,7 +431,7 @@ func finalizeArgsForScanf(realArgs []interface{}, args []interface{}) {
 	for i, arg := range realArgs {
 		if reflect.TypeOf(arg) == typeOfStringRef {
 			s := *arg.(*string)
-			copy(args[i].([]byte), []byte(s))
+			copy(args[i].([]byte), []byte(s+"\x00"))
 		} else {
 			GoPointerToCPointer(arg, args[i])
 		}
@@ -699,8 +704,9 @@ func Scanf(format []byte, args ...interface{}) int32 {
 }
 
 func Sscanf(str []byte, format []byte, args ...interface{}) int32 {
+	wws := bytes.Replace(str, []byte("\n"), []byte{' '}, -1) // without newline
 	realArgs := prepareArgsForScanf(args)
-	n, _ := fmt.Sscanf(CStringToString(str), CStringToString(format), realArgs...)
+	n, _ := fmt.Sscanf(CStringToString(wws), CStringToString(format), realArgs...)
 	finalizeArgsForScanf(realArgs, args)
 	return int32(n)
 }
diff --git a/program/cstd.go b/program/cstd.go
index 53f7553..f04a93e 100644
--- a/program/cstd.go
+++ b/program/cstd.go
@@ -175,7 +175,7 @@ func memcpy(dst, src interface{}, size uint32) interface{} {
 //---
 // __assert_fail from assert.h
 // c function : bool __assert_fail(const char*, const char*, unsigned int, const char*)
-// dep pkg    : os github.com/Konstantin8105/c4go/noarch
+// dep pkg    : fmt os github.com/Konstantin8105/c4go/noarch
 // dep func   :
 func __assert_fail(
 	expression, filePath []byte,
diff --git a/scripts/scripts.txt b/scripts/scripts.txt
index 490bb04..768b0f2 100644
--- a/scripts/scripts.txt
+++ b/scripts/scripts.txt
@@ -12,7 +12,7 @@ Calculate warnings : ./testdata/9wm
 Calculate warnings : ./testdata/ed
 		After transpiling : 0 warnings.
 		Go build : 7 warnings
-		Unsafe   : 167
+		Unsafe   : 162
 
 Calculate warnings in file: ./testdata/kilo/kilo.go
 		After transpiling : 0 warnings.
@@ -52,11 +52,11 @@ Calculate warnings in file: ./testdata/neatrefer/neatrefer.go
 Calculate warnings : ./testdata/nuklear/x11.go
 		After transpiling : 9 warnings.
 		Go build : 12 warnings
-		Unsafe   : 883
+		Unsafe   : 877
 Calculate warnings : ./testdata/nuklear/x11_opengl2.go
 		After transpiling : 19 warnings.
 		Go build : 12 warnings
-		Unsafe   : 1069
+		Unsafe   : 1061
 
 Calculate warnings in file: ./testdata/neatroff/neatroff.go
 		After transpiling : 3 warnings.
@@ -74,7 +74,7 @@ Calculate warnings : ./testdata/redis/linenoise.go
 Calculate warnings : ./testdata/redis/redis_cli.go
 		After transpiling : 0 warnings.
 		Go build : 50 warnings
-		Unsafe   : 262
+		Unsafe   : 261
 Calculate warnings : ./testdata/redis/sds.go
 		After transpiling : 0 warnings.
 		Go build : 43 warnings
@@ -98,7 +98,7 @@ Calculate warnings in file: ./testdata/progress/progress.go
 Calculate warnings in file: ./testdata/SQLITE/sqlite.go
 		After transpiling : 1 warnings.
 		Go build : 1 warnings
-		Unsafe   : 2373
+		Unsafe   : 2348
 
 Calculate warnings in file: ./testdata/tiny-web-server/tiny-web-server.go
 		After transpiling : 0 warnings.
@@ -108,5 +108,5 @@ Calculate warnings in file: ./testdata/tiny-web-server/tiny-web-server.go
 Calculate warnings in file: testdata/vorbis/vorbis.go
 		After transpiling : 0 warnings.
 		Go build : 18 warnings
-		Unsafe   : 132
+		Unsafe   : 128
 
diff --git a/transpiler/branch.go b/transpiler/branch.go
index bd88222..11866dc 100644
--- a/transpiler/branch.go
+++ b/transpiler/branch.go
@@ -57,7 +57,10 @@ func transpileIfStmt(n *ast.IfStmt, p *program.Program) (
 
 	// From here on there must be 4 children.
 	if len(children) != 4 {
-		panic(fmt.Sprintf("Expected 4 children in IfStmt, got %#v", children))
+		children = append([]ast.Node{nil}, children...)
+	}
+	if len(children) != 4 {
+		children = append(children, nil)
 	}
 
 	// Maybe we will discover what the nil value is?
@@ -462,17 +465,29 @@ func transpileForStmt(n *ast.ForStmt, p *program.Program) (
 //    |     `-DeclRefExpr 0x2530c78 <col:3> 'int' lvalue Var 0x25306f8 'i' 'int'
 func transpileWhileStmt(n *ast.WhileStmt, p *program.Program) (
 	goast.Stmt, []goast.Stmt, []goast.Stmt, error) {
+
+	for i := 0; i < len(n.Children()); i++ {
+		if n.ChildNodes[0] == nil {
+			n.ChildNodes = n.ChildNodes[1:]
+		}
+		break
+	}
+
 	var forOperator ast.ForStmt
 	forOperator.AddChild(nil)
 	forOperator.AddChild(nil)
-	forOperator.AddChild(n.Children()[1])
+	forOperator.AddChild(n.Children()[0])
 	forOperator.AddChild(nil)
-	if n.Children()[2] == nil {
-		// added for case if WHILE haven't body, for example:
-		// while(0);
-		n.Children()[2] = &ast.CompoundStmt{}
+	if len(n.Children()) > 1 {
+		if n.Children()[1] == nil {
+			// added for case if WHILE haven't body, for example:
+			// while(0);
+			n.Children()[1] = &ast.CompoundStmt{}
+		}
+		forOperator.AddChild(n.Children()[1])
+	} else {
+		forOperator.AddChild(&ast.CompoundStmt{})
 	}
-	forOperator.AddChild(n.Children()[2])
 
 	return transpileForStmt(&forOperator, p)
 }
diff --git a/transpiler/enum.go b/transpiler/enum.go
index 6402c7f..98e6eae 100644
--- a/transpiler/enum.go
+++ b/transpiler/enum.go
@@ -138,6 +138,13 @@ func transpileEnumDeclWithType(p *program.Program, n *ast.EnumDecl, enumType str
 		//         |     `-IntegerLiteral 'int' 2
 		//         `-IntegerLiteral 'int' 8
 		//
+		// specific for clang 8:
+		// EnumConstantDecl  _ISalpha 'int'
+		// `-ConstantExpr 'int'
+		//   `-ParenExpr 'int'
+		//     `-ConditionalOperator 'int'
+		//       ...
+		//
 		//	_ISalpha = func() int32 {
 		//		if 2 < 8 {
 		//			return 1 << uint64(2) << uint64(8)
@@ -145,6 +152,9 @@ func transpileEnumDeclWithType(p *program.Program, n *ast.EnumDecl, enumType str
 		//		return 1 << uint64(2) >> uint64(8)
 		//	}()
 		if len(child.Children()) == 1 {
+			if ce, ok := child.Children()[0].(*ast.ConstantExpr); ok && len(ce.ChildNodes) > 0 {
+				child.ChildNodes[0] = ce.ChildNodes[0]
+			}
 			if par, ok := child.Children()[0].(*ast.ParenExpr); ok {
 				if cond, ok := par.Children()[0].(*ast.ConditionalOperator); ok {
 					if bin, ok := cond.Children()[0].(*ast.BinaryOperator); ok && bin.Operator == "<" {
@@ -246,7 +256,7 @@ func transpileEnumDeclWithType(p *program.Program, n *ast.EnumDecl, enumType str
 		default:
 			e = val
 			p.AddMessage(p.GenerateWarningMessage(
-				fmt.Errorf("Add support of continues counter for type : %#v",
+				fmt.Errorf("Add support of continues counter for Go type : %#v",
 					v), n))
 		}
 
diff --git a/transpiler/transpiler.go b/transpiler/transpiler.go
index 91d919e..09df262 100644
--- a/transpiler/transpiler.go
+++ b/transpiler/transpiler.go
@@ -271,6 +271,16 @@ func transpileToExpr(node ast.Node, p *program.Program, exprIsStmt bool) (
 	case *ast.VAArgExpr:
 		expr, exprType, preStmts, postStmts, err = transpileVAArgExpr(n, p)
 
+	case *ast.ConstantExpr:
+		switch len(n.Children()) {
+		case 0:
+			// ignore
+		case 1:
+			expr, exprType, preStmts, postStmts, err = transpileToExpr(n.Children()[0], p, exprIsStmt)
+		default:
+			err = fmt.Errorf("ConstantExpr: %v. has many nodes", err)
+		}
+
 	case *ast.VisibilityAttr:
 		// ignore
 


Test patch:
diff --git a/ast/constant_expr_test.go b/ast/constant_expr_test.go
new file mode 100644
index 0000000..a4cd4e1
--- /dev/null
+++ b/ast/constant_expr_test.go
@@ -0,0 +1,18 @@
+package ast
+
+import (
+	"testing"
+)
+
+func TestConstantExpr(t *testing.T) {
+	nodes := map[string]Node{
+		`0x28f4a70 <line:223:7> 'int'`: &ConstantExpr{
+			Addr:       0x28f4a70,
+			Pos:        NewPositionFromString("line:223:7"),
+			Type:       "int",
+			ChildNodes: []Node{},
+		},
+	}
+
+	runNodeTests(t, nodes)
+}
diff --git a/ast/if_stmt_test.go b/ast/if_stmt_test.go
index 52c1df1..9396e6d 100644
--- a/ast/if_stmt_test.go
+++ b/ast/if_stmt_test.go
@@ -11,6 +11,12 @@ func TestIfStmt(t *testing.T) {
 			Pos:        NewPositionFromString("line:11:7, line:18:7"),
 			ChildNodes: []Node{},
 		},
+		`0x25a5f78 <line:1329:8, line:1337:26> has_else`: &IfStmt{
+			Addr:       0x25a5f78,
+			Pos:        NewPositionFromString("line:1329:8, line:1337:26"),
+			HasElse:    true,
+			ChildNodes: []Node{},
+		},
 	}
 
 	runNodeTests(t, nodes)
diff --git a/tests/stdio.c b/tests/stdio.c
index 1bc30bd..0847b5e 100644
--- a/tests/stdio.c
+++ b/tests/stdio.c
@@ -196,7 +196,7 @@ void test_fscanf()
     pFile = fopen("./testdata/myfile2.txt", "w+");
     is_not_null(pFile);
 
-    fprintf(pFile, "%f \r\n %s %d %s", 3.1416, "PI", 42, "end");
+    fprintf(pFile, "%f \r\n\t\n %s %d %s", 3.1416, "PI", 42, "end");
     rewind(pFile);
     fscanf(pFile, "%f", &f);
     fscanf(pFile, "%s", str);
@@ -229,6 +229,20 @@ void test_fscanf()
 
     // remove temp file
     is_eq(remove("./testdata/myfile2.txt"), 0)
+
+    // test file fscan.txt
+	FILE * in = fopen("./tests/stdio_fscan.txt", "r");
+	char dummy[128];
+
+	for(int iter = 0;iter < 10;iter++)
+	{
+	     int e = fscanf(in,"%s", dummy);
+	     printf("fscan : iter[%d] : err = %d\n", iter, e);
+	     if (e < 0) {
+	  	 	break;
+	     }
+	     printf("fscan : iter[%d] : str = %s\n", iter, dummy);
+	}
 }
 
 void test_fgetc()
@@ -589,11 +603,13 @@ void test_getline()
 
 void test_sscanf()
 {
-    char sentence[] = "Rudolph is 12 years old";
+    char sentence[] = "Example\nRudolph is 12 years old";
+    char header[50];
     char temp[50];
     char str[20];
     int i;
-    sscanf(sentence, "%s %s %d", str, temp, &i);
+    sscanf(sentence, "%s %s %s %d", header, str, temp, &i);
+	printf("Header: %s\n", header);
     is_eq(i, 12);
     is_streq(str, "Rudolph");
 }
diff --git a/tests/stdio_fscan.txt b/tests/stdio_fscan.txt
new file mode 100644
index 0000000..0c4a407
--- /dev/null
+++ b/tests/stdio_fscan.txt
@@ -0,0 +1,7 @@
+
+#-----------#
+# Example 1 #
+#-----------#
+
+#========= | POINTS | =========# 
+9 # number of points