Repository: Konstantin8105/c4go
Pull request #407 (2019-04-15 12:16:16)

Add main flag Debug

codecov[bot]: # [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/407?src=pr&el=h1) Report
> Merging [#407](https://codecov.io/gh/Konstantin8105/c4go/pull/407?src=pr&el=desc) into [master](https://codecov.io/gh/Konstantin8105/c4go/commit/66dc36ce96e8a4ffb46ab57b32570021898b9ea2?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/Konstantin8105/c4go/pull/407/graphs/tree.svg?width=650&token=esH2rHXlZ2&height=150&src=pr)](https://codecov.io/gh/Konstantin8105/c4go/pull/407?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master     #407   +/-   ##
=======================================
  Coverage   85.39%   85.39%           
=======================================
  Files         190      190           
  Lines       11214    11214           
=======================================
  Hits         9576     9576           
  Misses       1168     1168           
  Partials      470      470
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/407?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/407?src=pr&el=footer). Last update [66dc36c...44b2a3c](https://codecov.io/gh/Konstantin8105/c4go/pull/407?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Konstantin8105: Close #405

Patch:
diff --git a/.gitignore b/.gitignore
index 2305ea1..2316133 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,7 @@
 /.vscode
 *.coverprofile
 tests/*.go
+tests/debug*.c
+tests/debug*.h
 examples/*.go
+debug.txt
diff --git a/ast/linkage_spec_decl.go b/ast/linkage_spec_decl.go
index 2041c12..78c7dc7 100644
--- a/ast/linkage_spec_decl.go
+++ b/ast/linkage_spec_decl.go
@@ -19,7 +19,7 @@ func parseLinkageSpecDecl(line string) *LinkageSpecDecl {
 		`<(?P<position>.*)>
 		(?P<position2> col:\d+| line:\d+:\d+)?
 		(?P<implicit> implicit)?
-		(?P<name> \w+?)?
+		(?P<name> .*)?
 		`,
 		line,
 	)
diff --git a/debug.go b/debug.go
new file mode 100644
index 0000000..cb1a418
--- /dev/null
+++ b/debug.go
@@ -0,0 +1,207 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"sort"
+	"strings"
+
+	"github.com/Konstantin8105/c4go/ast"
+	"github.com/Konstantin8105/c4go/preprocessor"
+)
+
+func generateDebugCCode(args ProgramArgs, lines []string, filePP preprocessor.FilePP) (
+	err error) {
+	if args.verbose {
+		fmt.Fprintln(os.Stdout, "Convert ast lines to ast tree")
+	}
+
+	// convert lines to tree ast
+	tree, errs := FromLinesToTree(args.verbose, lines, filePP)
+	for i := range errs {
+		fmt.Fprintf(os.Stderr, "AST error #%d:\n%v\n",
+			i, errs[i].Error())
+	}
+	if tree == nil {
+		return fmt.Errorf("Cannot create tree: tree is nil. Please try another version of clang")
+	}
+
+	// Example of AST:
+	//
+	// TranslationUnitDecl 0x35e7b40 <<invalid sloc>> <invalid sloc>
+	// |-TypedefDecl
+	// | `-...
+	// |-FunctionDecl used a 'void (int *)'
+	// |-FunctionDecl
+	// | |-ParmVarDecl
+	// | `-CompoundStmt
+	// |   `-...
+
+	if len(tree) == 0 {
+		return fmt.Errorf("tree is empty")
+	}
+
+	if args.verbose {
+		fmt.Fprintln(os.Stdout, "Walking by tree...")
+	}
+
+	type funcPos struct {
+		name string
+		pos  ast.Position
+	}
+
+	// map[filename] []funcPos
+	funcPoses := map[string][]funcPos{}
+
+	for i := range tree {
+		tr, ok := tree[i].(*ast.TranslationUnitDecl)
+		if !ok {
+			return fmt.Errorf("first node %d is not TranslationUnitDecl: %d", i, tree[i])
+		}
+		for j := range tr.Children() {
+			// is it FunctionDecl
+			fd, ok := tr.Children()[j].(*ast.FunctionDecl)
+			if !ok {
+				continue
+			}
+			if len(fd.Children()) == 0 {
+				continue
+			}
+			// have a body
+			mst, ok := fd.Children()[len(fd.Children())-1].(*ast.CompoundStmt)
+			if !ok {
+				continue
+			}
+			// is user source
+			if !filePP.IsUserSource(mst.Position().File) {
+				continue
+			}
+
+			if args.verbose {
+				fmt.Fprintf(os.Stdout, "find function : %s\n", fd.Name)
+			}
+
+			// save position
+			f := funcPos{
+				name: fd.Name,
+				pos:  mst.Position(),
+			}
+			if sl, ok := funcPoses[mst.Position().File]; ok {
+				sl = append(sl, f)
+				funcPoses[mst.Position().File] = sl
+				continue
+			}
+			funcPoses[mst.Position().File] = append([]funcPos{}, f)
+		}
+	}
+
+	if args.verbose {
+		fmt.Fprintf(os.Stdout, "found %d files with functions\n", len(funcPoses))
+	}
+
+	for file, positions := range funcPoses {
+		// sort from end to begin
+		sort.Slice(positions, func(i, j int) bool {
+			if positions[i].pos.Line == positions[j].pos.Line {
+				return positions[i].pos.Column < positions[j].pos.Column
+			}
+			return positions[i].pos.Line < positions[j].pos.Line
+		})
+
+		// read present file
+		dat, err := ioutil.ReadFile(file)
+		if err != nil {
+			return err
+		}
+
+		if args.verbose {
+			fmt.Fprintln(os.Stdout, "inject debug information in file: ", file)
+		}
+
+		// inject function
+		lines := bytes.Split(dat, []byte("\n"))
+		for k := len(positions) - 1; k >= 0; k-- {
+
+			pos := positions[k].pos
+			if pos.Line-1 >= len(lines) {
+				return fmt.Errorf("try to add debug on outside of allowable line: %v", pos)
+			}
+			if pos.Column-1 >= len(lines[pos.Line-1]) {
+				return fmt.Errorf("try to add debug on outside of allowable column: %v", pos)
+			}
+			if lines[pos.Line-1][pos.Column-1] != '{' {
+				return fmt.Errorf("unacceptable char '{' : %c", lines[pos.Line-1][pos.Column-1])
+			}
+
+			lines[pos.Line-1] = append(lines[pos.Line-1][:pos.Column],
+				append([]byte(fmt.Sprintf("%s(%d,\"%s\");", debugFunctionName, pos.Line, positions[k].name)), lines[pos.Line-1][pos.Column:]...)...)
+		}
+
+		// add main debug function
+		lines = append([][]byte{[]byte(debugCode())}, lines...)
+
+		filename := file
+		// create a new filename
+		if index := strings.LastIndex(file, "/"); index >= 0 {
+			filename = file[:index+1] + args.debugPrefix + file[index+1:]
+		} else {
+			filename = args.debugPrefix + file
+		}
+
+		if args.verbose {
+			fmt.Fprintln(os.Stdout, "Write file with debug information in file: ", filename)
+		}
+
+		// save file with prefix+filename
+		err = ioutil.WriteFile(filename, bytes.Join(lines, []byte{'\n'}), 0644)
+		if err != nil {
+			return err
+		}
+	}
+
+	// Example for input function input data:
+	//
+	// FunctionDecl used readline 'char *(char *, FILE *, char *)'
+	// |-ParmVarDecl used string 'char *'
+	// |-ParmVarDecl used infile 'FILE *'
+	// |-ParmVarDecl used infilename 'char *'
+	// `-CompoundStmt
+	//   |-...
+	//
+	// FunctionDecl used tolower 'long (int, int)'
+	// |-ParmVarDecl used a 'int'
+	// |-ParmVarDecl used b 'int'
+	// `-CompoundStmt
+	//   `-...
+
+	return nil
+}
+
+const debugFunctionName string = "c4go_debug_function_name"
+
+func debugCode() string {
+	return `
+#include <stdio.h>
+#include <stdlib.h>
+
+FILE * c4go_get_debug_file()
+{
+	FILE * file;
+	file = fopen("./debug.txt","a");
+	if(file==NULL){
+		exit(53);
+	};
+	return file;
+}
+
+void c4go_debug_function_name(int line, char * functionName)
+{
+	FILE * file = c4go_get_debug_file();
+	fprintf(file,"Line: %d. Function name: %s\n",line, functionName);
+	fclose(file);
+}
+
+`
+}
diff --git a/main.go b/main.go
index ed9c9d9..1868947 100644
--- a/main.go
+++ b/main.go
@@ -11,7 +11,6 @@
 package main
 
 import (
-	"errors"
 	"flag"
 	"fmt"
 	"io"
@@ -46,22 +45,34 @@ var astout io.Writer = os.Stdout
 // Do not instantiate this directly. Instead use DefaultProgramArgs(); then
 // modify any specific attributes.
 type ProgramArgs struct {
+	state          ProgramState
 	verbose        bool
-	ast            bool
 	inputFiles     []string
 	clangFlags     []string
 	outputFile     string
 	packageName    string
 	cppCode        bool
 	outsideStructs bool
+
+	// for debugging
+	debugPrefix string
 }
 
+type ProgramState int
+
+const (
+	StateAst ProgramState = iota
+	StateTranspile
+	StateDebug
+)
+
 // DefaultProgramArgs default value of ProgramArgs
 func DefaultProgramArgs() ProgramArgs {
 	return ProgramArgs{
 		verbose:     false,
-		ast:         false,
+		state:       StateTranspile,
 		packageName: "main",
+		debugPrefix: "debug.",
 		clangFlags:  []string{},
 	}
 }
@@ -326,29 +337,33 @@ func avoidGoKeywords(tree []ast.Node) {
 
 // Start begins transpiling an input file.
 func Start(args ProgramArgs) (err error) {
+	if args.verbose {
+		fmt.Fprintln(os.Stdout, "Reading clang AST tree...")
+	}
+
 	lines, filePP, err := generateAstLines(args)
 	if err != nil {
 		return
 	}
 
-	if args.verbose {
-		fmt.Fprintln(os.Stdout, "Reading clang AST tree...")
-	}
-	if args.ast {
+	switch args.state {
+	case StateAst:
 		for _, l := range lines {
 			fmt.Fprintln(astout, l)
 		}
 		fmt.Fprintln(astout)
 
-		return nil
-	}
+	case StateTranspile:
+		err = generateGoCode(args, lines, filePP)
 
-	err = generateGoCode(args, lines, filePP)
-	if err != nil {
-		return
+	case StateDebug:
+		err = generateDebugCCode(args, lines, filePP)
+
+	default:
+		err = fmt.Errorf("Program state `%d` is not implemented", args.state)
 	}
 
-	return nil
+	return err
 }
 
 func generateAstLines(args ProgramArgs) (lines []string, filePP preprocessor.FilePP, err error) {
@@ -408,36 +423,30 @@ func generateAstLines(args ProgramArgs) (lines []string, filePP preprocessor.Fil
 		errBody, _ := exec.Command(
 			compiler, append(compilerFlag, ppFilePath)...).CombinedOutput()
 
-		panic("clang failed: " + err.Error() + ":\n\n" + string(errBody))
+		panic(compiler + " failed: " + err.Error() + ":\n\n" + string(errBody))
 	}
 	lines = strings.Split(string(astPP), "\n")
 
 	return
 }
 
-func generateGoCode(args ProgramArgs, lines []string, filePP preprocessor.FilePP) (
-	err error) {
-
-	p := program.NewProgram()
-	p.Verbose = args.verbose
-	p.PreprocessorFile = filePP
-
+func FromLinesToTree(verbose bool, lines []string, filePP preprocessor.FilePP) (tree []ast.Node, errs []error) {
 	// Converting to nodes
-	if args.verbose {
+	if verbose {
 		fmt.Fprintln(os.Stdout, "Converting to nodes...")
 	}
 	nodes, astErrors := convertLinesToNodesParallel(lines)
 	for i := range astErrors {
-		p.AddMessage(fmt.Sprintf(
+		errs = append(errs, fmt.Errorf(
 			"/"+"* AST Error :\n%v\n*"+"/",
 			astErrors[i].Error()))
 	}
 
 	// build tree
-	if args.verbose {
+	if verbose {
 		fmt.Fprintln(os.Stdout, "Building tree...")
 	}
-	tree := buildTree(nodes, 0)
+	tree = buildTree(nodes, 0)
 	ast.FixPositions(tree)
 
 	// Repair the floating literals. See RepairFloatingLiteralsFromSource for
@@ -445,17 +454,37 @@ func generateGoCode(args ProgramArgs, lines []string, filePP preprocessor.FilePP
 	floatingErrors := ast.RepairFloatingLiteralsFromSource(tree[0], filePP)
 
 	for _, fErr := range floatingErrors {
-		message := fmt.Sprintf("could not read exact floating literal: %s",
-			fErr.Err.Error())
-		p.AddMessage(p.GenerateWarningMessage(errors.New(message), fErr.Node))
+		errs = append(errs, fmt.Errorf("could not read exact floating literal: %s",
+			fErr.Err.Error()))
 	}
 
 	// avoid Go keywords
-	if args.verbose {
+	if verbose {
 		fmt.Fprintln(os.Stdout, "Modify nodes for avoid Go keywords...")
 	}
 	avoidGoKeywords(tree)
 
+	return
+}
+
+func generateGoCode(args ProgramArgs, lines []string, filePP preprocessor.FilePP) (
+	err error) {
+
+	p := program.NewProgram()
+	p.Verbose = args.verbose
+	p.PreprocessorFile = filePP
+
+	// convert lines to tree ast
+	tree, errs := FromLinesToTree(args.verbose, lines, filePP)
+	for i := range errs {
+		fmt.Fprintf(os.Stderr, "AST error #%d:\n%v\n",
+			i, errs[i].Error())
+		p.AddMessage(errs[i].Error())
+	}
+	if tree == nil {
+		return fmt.Errorf("Cannot create tree: tree is nil. Please try another version of clang")
+	}
+
 	outputFilePath := args.outputFile
 
 	if outputFilePath == "" {
@@ -478,10 +507,6 @@ func generateGoCode(args ProgramArgs, lines []string, filePP preprocessor.FilePP
 	source, err = transpiler.TranspileAST(args.outputFile, args.packageName, args.outsideStructs,
 		p, tree[0].(ast.Node))
 	if err != nil {
-		for i := range astErrors {
-			fmt.Fprintf(os.Stderr, "AST error #%d:\n%v\n",
-				i, astErrors[i].Error())
-		}
 		return fmt.Errorf("cannot transpile AST : %v", err)
 	}
 
@@ -548,6 +573,17 @@ func runCommand() int {
 			"cpp", false, "transpile CPP code")
 		astHelpFlag = astCommand.Bool(
 			"h", false, "print help information")
+
+		debugCommand = flag.NewFlagSet(
+			"debug", flag.ContinueOnError)
+		debugCppFlag = debugCommand.Bool(
+			"cpp", false, "transpile CPP code")
+		debugVerboseFlag = debugCommand.Bool(
+			"V", false, "print progress as comments")
+		prefixDebugFlag = debugCommand.String(
+			"p", "debug.", "prefix of output C filename with addition debug informations")
+		debugHelpFlag = debugCommand.Bool(
+			"h", false, "print help information")
 	)
 	var clangFlags inputDataFlags
 	transpileCommand.Var(&clangFlags,
@@ -556,6 +592,9 @@ func runCommand() int {
 	astCommand.Var(&clangFlags,
 		"clang-flag",
 		"Pass arguments to clang. You may provide multiple -clang-flag items.")
+	debugCommand.Var(&clangFlags,
+		"clang-flag",
+		"Pass arguments to clang. You may provide multiple -clang-flag items.")
 
 	// TODO : add example for starters
 
@@ -564,6 +603,7 @@ func runCommand() int {
 		usage += "Commands:\n"
 		usage += "  transpile\ttranspile an input C source file or files to Go\n"
 		usage += "  ast\t\tprint AST before translated Go code\n"
+		usage += "  debug\t\tadd debug information in C source\n"
 		usage += "  version\tprint version of c4go\n"
 		usage += "\n"
 		fmt.Fprintf(stderr, usage, os.Args[0])
@@ -573,6 +613,7 @@ func runCommand() int {
 
 	transpileCommand.SetOutput(stderr)
 	astCommand.SetOutput(stderr)
+	debugCommand.SetOutput(stderr)
 
 	flag.Parse()
 
@@ -592,15 +633,16 @@ func runCommand() int {
 		}
 
 		if *astHelpFlag || astCommand.NArg() == 0 {
-			fmt.Fprintf(stderr, "Usage: %s ast file.c\n", os.Args[0])
+			fmt.Fprintf(stderr, "Usage: %s ast [-cpp] [-clang-flag values] file.c\n", os.Args[0])
 			astCommand.PrintDefaults()
 			return 3
 		}
 
-		args.ast = true
+		args.state = StateAst
 		args.inputFiles = astCommand.Args()
 		args.clangFlags = clangFlags
 		args.cppCode = *astCppFlag
+
 	case "transpile":
 		err := transpileCommand.Parse(os.Args[2:])
 		if err != nil {
@@ -610,12 +652,13 @@ func runCommand() int {
 
 		if *transpileHelpFlag || transpileCommand.NArg() == 0 {
 			fmt.Fprintf(stderr,
-				"Usage: %s transpile [-V] [-o file.go] [-p package] [-cpuprofile cpu.out] file1.c ...\n",
+				"Usage: %s transpile [-V] [-o file.go] [-cpp] [-p package] [-clang-flag values] [-cpuprofile cpu.out] file1.c ...\n",
 				os.Args[0])
 			transpileCommand.PrintDefaults()
 			return 5
 		}
 
+		args.state = StateTranspile
 		args.inputFiles = transpileCommand.Args()
 		args.outputFile = *outputFlag
 		args.packageName = *packageFlag
@@ -636,6 +679,26 @@ func runCommand() int {
 			defer pprof.StopCPUProfile()
 		}
 
+	case "debug":
+		err := debugCommand.Parse(os.Args[2:])
+		if err != nil {
+			fmt.Fprintf(os.Stdout, "debug command cannot parse: %v", err)
+			return 12
+		}
+
+		if *debugHelpFlag || debugCommand.NArg() == 0 {
+			fmt.Fprintf(stderr, "Usage: %s debug [-cpp] [-clang-flag values] file.c\n", os.Args[0])
+			debugCommand.PrintDefaults()
+			return 30
+		}
+
+		args.state = StateDebug
+		args.inputFiles = debugCommand.Args()
+		args.verbose = *debugVerboseFlag
+		args.debugPrefix = *prefixDebugFlag
+		args.clangFlags = clangFlags
+		args.cppCode = *debugCppFlag
+
 	case "version":
 		fmt.Fprint(stderr, version.Version())
 		return 0


Test patch:
diff --git a/.snapshots/c4go-TestCLI-func1-AstHelpFlag b/.snapshots/c4go-TestCLI-func1-AstHelpFlag
index c017f8b..02590a8 100644
--- a/.snapshots/c4go-TestCLI-func1-AstHelpFlag
+++ b/.snapshots/c4go-TestCLI-func1-AstHelpFlag
@@ -1,4 +1,4 @@
-(*bytes.Buffer)(Usage: test ast file.c
+(*bytes.Buffer)(Usage: test ast [-cpp] [-clang-flag values] file.c
   -clang-flag value
     	Pass arguments to clang. You may provide multiple -clang-flag items.
   -cpp
diff --git a/.snapshots/c4go-TestCLI-func1-AstNoFilesHelp b/.snapshots/c4go-TestCLI-func1-AstNoFilesHelp
index c017f8b..02590a8 100644
--- a/.snapshots/c4go-TestCLI-func1-AstNoFilesHelp
+++ b/.snapshots/c4go-TestCLI-func1-AstNoFilesHelp
@@ -1,4 +1,4 @@
-(*bytes.Buffer)(Usage: test ast file.c
+(*bytes.Buffer)(Usage: test ast [-cpp] [-clang-flag values] file.c
   -clang-flag value
     	Pass arguments to clang. You may provide multiple -clang-flag items.
   -cpp
diff --git a/.snapshots/c4go-TestCLI-func1-DebugHelpFlag b/.snapshots/c4go-TestCLI-func1-DebugHelpFlag
new file mode 100644
index 0000000..6bedc72
--- /dev/null
+++ b/.snapshots/c4go-TestCLI-func1-DebugHelpFlag
@@ -0,0 +1,10 @@
+(*bytes.Buffer)(Usage: test debug [-cpp] [-clang-flag values] file.c
+  -V	print progress as comments
+  -clang-flag value
+    	Pass arguments to clang. You may provide multiple -clang-flag items.
+  -cpp
+    	transpile CPP code
+  -h	print help information
+  -p string
+    	prefix of output C filename with addition debug informations (default "debug.")
+)
diff --git a/.snapshots/c4go-TestCLI-func1-DebugNoFilesHelp b/.snapshots/c4go-TestCLI-func1-DebugNoFilesHelp
new file mode 100644
index 0000000..6bedc72
--- /dev/null
+++ b/.snapshots/c4go-TestCLI-func1-DebugNoFilesHelp
@@ -0,0 +1,10 @@
+(*bytes.Buffer)(Usage: test debug [-cpp] [-clang-flag values] file.c
+  -V	print progress as comments
+  -clang-flag value
+    	Pass arguments to clang. You may provide multiple -clang-flag items.
+  -cpp
+    	transpile CPP code
+  -h	print help information
+  -p string
+    	prefix of output C filename with addition debug informations (default "debug.")
+)
diff --git a/.snapshots/c4go-TestCLI-func1-TranspileHelpFlag b/.snapshots/c4go-TestCLI-func1-TranspileHelpFlag
index 3816338..71abf5c 100644
--- a/.snapshots/c4go-TestCLI-func1-TranspileHelpFlag
+++ b/.snapshots/c4go-TestCLI-func1-TranspileHelpFlag
@@ -1,4 +1,4 @@
-(*bytes.Buffer)(Usage: test transpile [-V] [-o file.go] [-p package] [-cpuprofile cpu.out] file1.c ...
+(*bytes.Buffer)(Usage: test transpile [-V] [-o file.go] [-cpp] [-p package] [-clang-flag values] [-cpuprofile cpu.out] file1.c ...
   -V	print progress as comments
   -clang-flag value
     	Pass arguments to clang. You may provide multiple -clang-flag items.
diff --git a/.snapshots/c4go-TestCLI-func1-TranspileNoFilesHelp b/.snapshots/c4go-TestCLI-func1-TranspileNoFilesHelp
index 3816338..71abf5c 100644
--- a/.snapshots/c4go-TestCLI-func1-TranspileNoFilesHelp
+++ b/.snapshots/c4go-TestCLI-func1-TranspileNoFilesHelp
@@ -1,4 +1,4 @@
-(*bytes.Buffer)(Usage: test transpile [-V] [-o file.go] [-p package] [-cpuprofile cpu.out] file1.c ...
+(*bytes.Buffer)(Usage: test transpile [-V] [-o file.go] [-cpp] [-p package] [-clang-flag values] [-cpuprofile cpu.out] file1.c ...
   -V	print progress as comments
   -clang-flag value
     	Pass arguments to clang. You may provide multiple -clang-flag items.
diff --git a/ast/linkage_spec_decl_test.go b/ast/linkage_spec_decl_test.go
index 51c7cb7..2774bae 100644
--- a/ast/linkage_spec_decl_test.go
+++ b/ast/linkage_spec_decl_test.go
@@ -14,6 +14,14 @@ func TestLinkageSpecDecl(t *testing.T) {
 			Name:       "C",
 			ChildNodes: []Node{},
 		},
+		`0x266fad0 <line:74:1, line:94:1> line:74:8 C++`: &LinkageSpecDecl{
+			Addr:       0x266fad0,
+			Pos:        NewPositionFromString("line:74:1, line:94:1"),
+			Position2:  "line:74:8",
+			IsImplicit: false,
+			Name:       "C++",
+			ChildNodes: []Node{},
+		},
 	}
 
 	runNodeTests(t, nodes)
diff --git a/cli_test.go b/cli_test.go
index 366114d..fabcff1 100644
--- a/cli_test.go
+++ b/cli_test.go
@@ -35,6 +35,12 @@ var cliTests = map[string][]string{
 	// Test that help is printed if help flag is set, even if file is given
 	"AstHelpFlag": {"test", "ast", "-h", "foo.c"},
 
+	// Test that help is printed if no files are given
+	"DebugNoFilesHelp": {"test", "debug"},
+
+	// Test that help is printed if help flag is set, even if file is given
+	"DebugHelpFlag": {"test", "debug", "-h", "foo.c"},
+
 	// Test that version is printed
 	"Version": {"test", "version"},
 }
diff --git a/main_test.go b/main_test.go
index 9336471..bbea89e 100644
--- a/main_test.go
+++ b/main_test.go
@@ -74,6 +74,11 @@ func TestIntegrationScripts(t *testing.T) {
 	for _, file := range files {
 		t.Run(file, func(t *testing.T) {
 
+			defer func() {
+				// remove debug file
+				_ = os.Remove("debug.txt")
+			}()
+
 			// create subfolders for test
 			subFolder := buildFolder + separator + strings.Split(file, ".")[0] + separator
 
@@ -84,12 +89,18 @@ func TestIntegrationScripts(t *testing.T) {
 			}
 
 			// slice of program results
-			progs := [2]func(string, string, string, []string, []string) (string, error){
+			progs := []func(string, string, string, []string, []string) (string, error){
+				runCdebug,
 				runC,
 				runGo,
 			}
 
-			var results [2]string
+			// only for test "assert.c"
+			if strings.Contains(file, "assert.c") {
+				progs = progs[1:]
+			}
+
+			results := make([]string, len(progs))
 			var clangFlags []string
 
 			// specific of binding
@@ -135,78 +146,106 @@ func TestIntegrationScripts(t *testing.T) {
 				}
 			}
 
-			var (
-				cCombine  = results[0]
-				goCombine = results[1]
-			)
-
-			if cCombine != goCombine {
-				// Add addition debug information for lines like:
-				// build/tests/cast/main_test.go:195:1: expected '}', found 'type'
-				buildPrefix := buildFolder + "/tests/"
-				var output string
-				lines := strings.Split(goCombine, "\n")
-				amountSnippets := 0
-				for _, line := range lines {
-					line = strings.TrimSpace(line)
-					if !strings.HasPrefix(line, buildPrefix) {
-						continue
-					}
-					index := strings.Index(line, ":")
-					if index < 0 {
-						continue
-					}
-					filename := "./" + line[0:index]
-					output += "+========================+\n"
-					output += fmt.Sprintf("File : %s\n\n", filename)
-					if len(line) <= index+1 {
-						continue
-					}
-					line = line[index+1:]
-					index = strings.Index(line, ":")
-					if index < 0 {
-						continue
-					}
-					linePosition, err := strconv.Atoi(line[:index])
-					if err != nil {
-						continue
-					}
-					content, err := ioutil.ReadFile(filename)
-					if err != nil {
-						continue
-					}
-					fileLines := strings.Split(string(content), "\n")
-					start := linePosition - 20
-					if start < 0 {
-						start = 0
-					}
-					var indicator string
-					for i := start; i < linePosition+5 && i < len(fileLines); i++ {
-						if i == linePosition-1 {
-							indicator = "*"
-						} else {
-							indicator = " "
+			for i := 0; i < len(results)-1; i++ {
+				if results[i] != results[i+1] {
+					// Add addition debug information for lines like:
+					// build/tests/cast/main_test.go:195:1: expected '}', found 'type'
+					buildPrefix := buildFolder + "/tests/"
+					var output string
+					lines := strings.Split(results[i+1], "\n")
+					amountSnippets := 0
+					for _, line := range lines {
+						line = strings.TrimSpace(line)
+						if !strings.HasPrefix(line, buildPrefix) {
+							continue
+						}
+						index := strings.Index(line, ":")
+						if index < 0 {
+							continue
+						}
+						filename := "./" + line[0:index]
+						output += "+========================+\n"
+						output += fmt.Sprintf("File : %s\n\n", filename)
+						if len(line) <= index+1 {
+							continue
+						}
+						line = line[index+1:]
+						index = strings.Index(line, ":")
+						if index < 0 {
+							continue
+						}
+						linePosition, err := strconv.Atoi(line[:index])
+						if err != nil {
+							continue
+						}
+						content, err := ioutil.ReadFile(filename)
+						if err != nil {
+							continue
+						}
+						fileLines := strings.Split(string(content), "\n")
+						start := linePosition - 20
+						if start < 0 {
+							start = 0
+						}
+						var indicator string
+						for i := start; i < linePosition+5 && i < len(fileLines); i++ {
+							if i == linePosition-1 {
+								indicator = "*"
+							} else {
+								indicator = " "
+							}
+							output += fmt.Sprintf("Line : %3d %s: %s\n",
+								i+1, indicator, fileLines[i])
+						}
+						amountSnippets++
+						if amountSnippets >= 4 {
+							output += fmt.Sprintf("and more other snippets...\n")
+							break
 						}
-						output += fmt.Sprintf("Line : %3d %s: %s\n",
-							i+1, indicator, fileLines[i])
-					}
-					amountSnippets++
-					if amountSnippets >= 4 {
-						output += fmt.Sprintf("and more other snippets...\n")
-						break
 					}
+					t.Fatalf("\nParts of code:\n%s\n%s",
+						output,
+						util.ShowDiff(results[i], results[i+1]))
 				}
-				t.Fatalf("\nParts of code:\n%s\n%s",
-					output,
-					util.ShowDiff(cCombine, goCombine))
 			}
 			if flag.CommandLine.Lookup("test.v").Value.String() == "true" {
-				t.Log(goCombine)
+				t.Log(results[len(results)-1])
 			}
 		})
 	}
 }
 
+// compile and run C code
+func runCdebug(file, subFolder, stdin string, clangFlags, args []string) (string, error) {
+	pArgs := DefaultProgramArgs()
+	pArgs.inputFiles = []string{file}
+	pArgs.debugPrefix = "debug."
+	pArgs.state = StateDebug
+	pArgs.cppCode = strings.HasSuffix(file, "cpp")
+	pArgs.clangFlags = clangFlags
+	pArgs.verbose = (flag.CommandLine.Lookup("test.v").Value.String() == "true" || strings.Contains(file, "operators.c"))
+
+	// Compile Go
+	err := Start(pArgs)
+	if err != nil {
+		return "", fmt.Errorf("Cannot transpile : %v", err)
+	}
+
+	// create a new filename
+	if index := strings.LastIndex(file, "/"); index >= 0 {
+		file = file[:index+1] + pArgs.debugPrefix + file[index+1:]
+	} else {
+		file = pArgs.debugPrefix + file
+	}
+
+	defer func() {
+		// remove debug file
+		_ = os.Remove(file)
+	}()
+
+	return runC(file, subFolder, stdin, clangFlags, args)
+}
+
 // compile and run C code
 func runC(file, subFolder, stdin string, clangFlags, args []string) (string, error) {
 	cFileName := "a.out"
@@ -387,6 +426,7 @@ func runGo(file, subFolder, stdin string, clangFlags, args []string) (string, er
 	programArgs.inputFiles = []string{file}
 	programArgs.outputFile = subFolder + "main.go"
 	programArgs.clangFlags = clangFlags
+	programArgs.verbose = (flag.CommandLine.Lookup("test.v").Value.String() == "true" || strings.Contains(file, "operators.c"))
 	if strings.HasSuffix(file, "cpp") {
 		programArgs.cppCode = true
 	}
diff --git a/other_test.go b/other_test.go
index 7fb5cb1..0a4f678 100644
--- a/other_test.go
+++ b/other_test.go
@@ -148,7 +148,7 @@ func TestBookSources(t *testing.T) {
 					args := DefaultProgramArgs()
 					args.inputFiles = []string{file}
 					args.outputFile = goFile
-					args.ast = false
+					args.state = StateTranspile
 					args.verbose = false
 
 					if err := Start(args); err != nil {
@@ -280,7 +280,7 @@ func TestFrame3dd(t *testing.T) {
 		"-I" + folder + "microstran",
 	}
 	args.outputFile = folder + "src/main.go"
-	args.ast = false
+	args.state = StateTranspile
 	args.verbose = false
 
 	if err := Start(args); err != nil {
@@ -353,7 +353,7 @@ func TestCsparse(t *testing.T) {
 	}
 	args.clangFlags = []string{}
 	args.outputFile = folder + "main.go"
-	args.ast = false
+	args.state = StateTranspile
 	args.verbose = false
 
 	if err := Start(args); err != nil {
@@ -574,7 +574,7 @@ func TestMultifiles(t *testing.T) {
 				args.inputFiles = f.input
 				args.clangFlags = f.clang
 				args.outputFile = f.output
-				args.ast = false
+				args.state = StateTranspile
 				args.verbose = false
 
 				if err := Start(args); err != nil {
@@ -618,7 +618,7 @@ func TestKiloEditor(t *testing.T) {
 	args := DefaultProgramArgs()
 	args.inputFiles = []string{fileList[0]}
 	args.outputFile = goFile
-	args.ast = false
+	args.state = StateTranspile
 	args.verbose = false
 
 	if err := Start(args); err != nil {
@@ -678,7 +678,7 @@ func TestTinn(t *testing.T) {
 	args := DefaultProgramArgs()
 	args.inputFiles = fileList
 	args.outputFile = goFile
-	args.ast = false
+	args.state = StateTranspile
 	args.verbose = false
 
 	if err := Start(args); err != nil {
@@ -760,7 +760,7 @@ func TestSpringerproblem(t *testing.T) {
 	args := DefaultProgramArgs()
 	args.inputFiles = fileList
 	args.outputFile = goFile
-	args.ast = false
+	args.state = StateTranspile
 	args.verbose = false
 
 	if err := Start(args); err != nil {
diff --git a/scripts/test.sh b/scripts/test.sh
index 1d6d2f8..9bc604f 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -36,4 +36,6 @@ fi
 echo "End of coverage"
 
 # check race
-go test -tags=integration -run=TestIntegrationScripts/tests/ctype.c -race -v
+go test -tags=integration                     \
+	-run=TestIntegrationScripts/tests/ctype.c \
+	-race -v
diff --git a/tests/function.c b/tests/function.c
index df055d6..1921f16 100644
--- a/tests/function.c
+++ b/tests/function.c
@@ -55,7 +55,7 @@ int interface() { return 42; }
 int map() { return 42; }
 int package() { return 42; }
 int range() { return 42; }
-int select() { return 42; }
+// int select() { return 42; }
 int type() { return 42; }
 int var() { return 42; }
 int _() { return 42; }
@@ -216,7 +216,7 @@ void NullPointerCheck()
 
 int main()
 {
-    plan(65);
+    plan(64);
 
     test_string();
     test_null_function();
@@ -278,7 +278,7 @@ int main()
     is_eq(map(), 42);
     is_eq(package(), 42);
     is_eq(range(), 42);
-    is_eq(select(), 42);
+    // is_eq(select(), 42);
     is_eq(type(), 42);
     is_eq(var(), 42);
     is_eq(_(), 42);