├── 99dump ├── Makefile ├── README.md ├── all_test.go └── main.go ├── 99nm ├── Makefile ├── README.md ├── all_test.go └── main.go ├── 99prof ├── Makefile ├── README.md ├── all_test.go ├── main.go ├── profile_disabled.go └── profile_enabled.go ├── 99run ├── Makefile ├── README.md ├── all_test.go └── main.go ├── 99strace ├── Makefile ├── README.md ├── all_test.go ├── main.go ├── strace_disabled.go └── strace_enabled.go ├── 99trace ├── Makefile ├── README.md ├── all_test.go ├── main.go ├── trace_disabled.go └── trace_enabled.go ├── AUTHORS ├── CONTRIBUTORS ├── LICENSE ├── Makefile ├── README.md ├── all_test.go ├── ar.go ├── doc.go ├── examples ├── args │ └── args.c ├── define │ └── main.c ├── embedding │ ├── assets │ │ └── keepdir │ ├── main.c │ └── main.go ├── ffi │ ├── assets │ │ └── keepdir │ ├── lib42.c │ └── main.go ├── hello │ └── hello.c ├── include │ ├── foo │ │ └── main.h │ └── main.c ├── multifile │ ├── hello.c │ └── main.c ├── nm │ └── foo.c ├── plugin │ ├── lib42.c │ └── main.go ├── prof │ ├── bogomips.c │ └── fib.c ├── stack │ └── stack.c ├── strace │ ├── data.txt │ └── main.c └── xcb │ ├── drawingprimitives.c │ ├── eventex.c │ ├── fontcompleteexample.c │ ├── helloworld.c │ ├── mousecursorexample.c │ └── screen.c ├── lib ├── xau │ ├── .gitignore │ ├── README.md │ └── generator_linux.go └── xcb │ ├── .gitignore │ ├── README.md │ └── generator_linux.go ├── libtool.go ├── main.go └── testdata ├── issue4.c ├── libXau.la └── libxcb.la /99dump/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The 99c Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | .PHONY: all clean cover cpu editor internalError later mem nuke todo edit 6 | 7 | grep=--include=*.go --include=*.l --include=*.y --include=*.yy 8 | ngrep='TODOOK\|parser\.go\|scanner\.go\|.*_string\.go' 9 | 10 | all: editor 11 | go vet 2>&1 | grep -v $(ngrep) || true 12 | golint 2>&1 | grep -v $(ngrep) || true 13 | make todo 14 | unused . || true 15 | misspell *.go 16 | gosimple || true 17 | maligned || true 18 | unconvert -apply 19 | 20 | clean: 21 | go clean 22 | rm -f *~ *.test *.out 23 | 24 | cover: 25 | t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t 26 | 27 | cpu: clean 28 | go test -run @ -bench . -cpuprofile cpu.out 29 | go tool pprof -lines *.test cpu.out 30 | 31 | edit: 32 | @ 1>/dev/null 2>/dev/null gvim -p Makefile *.go 33 | 34 | editor: 35 | gofmt -l -s -w *.go 36 | go test -i 37 | go test 2>&1 | tee log 38 | go install 39 | 40 | internalError: 41 | egrep -ho '"internal error.*"' *.go | sort | cat -n 42 | 43 | later: 44 | @grep -n $(grep) LATER * || true 45 | @grep -n $(grep) MAYBE * || true 46 | 47 | mem: clean 48 | go test -run @ -bench . -memprofile mem.out -memprofilerate 1 -timeout 24h 49 | go tool pprof -lines -web -alloc_space *.test mem.out 50 | 51 | nuke: clean 52 | go clean -i 53 | 54 | todo: 55 | @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true 56 | @grep -nr $(grep) TODO * | grep -v $(ngrep) || true 57 | @grep -nr $(grep) BUG * | grep -v $(ngrep) || true 58 | @grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true 59 | -------------------------------------------------------------------------------- /99dump/README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | 1. Usage 4 | 1. Installation 5 | 1. Changelog 6 | 1. Sample 7 | 8 | # 99dump 9 | 10 | Command 99dump lists object and executable files produced by the 99c compiler. 11 | 12 | ### Usage 13 | 14 | 99dump [files...] 15 | 16 | ### Installation 17 | 18 | To install or update 99dump 19 | 20 | $ go get [-u] github.com/cznic/99c/99dump 21 | 22 | Online documentation: [godoc.org/github.com/cznic/99c/99dump](http://godoc.org/github.com/cznic/99c/99dump) 23 | 24 | ### Changelog 25 | 26 | 2017-10-09: Initial public release. 27 | 28 | ### Sample 29 | 30 | $ cd ../examples/hello/ 31 | $ ls * 32 | hello.c log 33 | $ 99c -c hello.c && 99dump hello.o 34 | ir.Objects hello.o: 35 | # [0]: *ir.FunctionDefinition { ExternalLinkage __builtin_fopen func(*int8,*int8)*struct{} X__FILE_TYPE__ /home/jnml/src/github.com/cznic/ccir/libc/builtin.h:45:15} [__filename __modes] 36 | 0x00000 panic ; /home/jnml/src/github.com/cznic/ccir/libc/builtin.h:45:15 37 | # [1]: *ir.FunctionDefinition { ExternalLinkage __builtin_strlen func(*int8)uint64 /home/jnml/src/github.com/cznic/ccir/libc/builtin.h:46:15} [__s] 38 | ... 39 | # [62]: *ir.FunctionDefinition { ExternalLinkage main func()int32 hello.c:3:1} [] 40 | 0x00000 result �, *int32 ; hello.c:3:12 41 | 0x00001 const 0x0, int32 ; hello.c:3:12 42 | 0x00002 store int32 ; hello.c:3:12 43 | 0x00003 drop int32 ; hello.c:3:12 44 | 0x00004 beginScope ; hello.c:3:12 45 | 0x00005 allocResult int32 ; hello.c:4:2 46 | 0x00006 global &printf, *func(*int8...)int32 ; hello.c:4:2 47 | 0x00007 arguments ; hello.c:4:9 48 | 0x00008 const "hello world\n", *int8 ; hello.c:4:9 49 | 0x00009 callfp 1, *func(*int8...)int32 ; hello.c:4:2 50 | 0x0000a drop int32 ; hello.c:4:2 51 | 0x0000b return ; hello.c:5:1 52 | 0x0000c endScope ; hello.c:5:1 53 | # [63]: *ir.DataDefinition { InternalLinkage main__func__0 [5]int8 -} "main"+0 54 | jnml@r550:~/src/github.com/cznic/99c/examples/hello$ 99c hello.o && 99dump a.out 55 | virtual.Binary a.out: code 0x00021, text 0x00010, data 0x00030, bss 0x00020, pc2func 2, pc2line 10 56 | 0x00000 call 0x2 ; - 57 | 0x00001 ffireturn ; - 58 | 59 | # _start 60 | 0x00002 func ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:13:1 61 | 0x00003 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 62 | 0x00004 push64 (ds) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 63 | 0x00005 push64 (ds+0x10) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 64 | 0x00006 push64 (ds+0x20) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 65 | 0x00007 #register_stdfiles ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 66 | 0x00008 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 67 | 0x00009 sub sp, 0x8 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 68 | 0x0000a arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 69 | 0x0000b push32 (ap-0x8) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 70 | 0x0000c push64 (ap-0x10) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 71 | 0x0000d call 0x16 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 72 | 0x0000e #exit ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 73 | 74 | 0x0000f builtin ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:16:1 75 | 0x00010 #register_stdfiles ; __register_stdfiles:89:1 76 | 0x00011 ffireturn ; __register_stdfiles:89:1 77 | 78 | 0x00012 add sp, 0x8 ; __builtin_exit:86:1 79 | 0x00013 #exit ; __builtin_exit:86:1 80 | 81 | 0x00014 call 0x16 ; __builtin_exit:86:1 82 | 0x00015 ffireturn ; __builtin_exit:86:1 83 | 84 | # main 85 | 0x00016 func ; hello.c:3:1 86 | 0x00017 push ap ; hello.c:3:1 87 | 0x00018 zero32 ; hello.c:3:1 88 | 0x00019 store32 ; hello.c:3:1 89 | 0x0001a arguments ; hello.c:3:1 90 | 0x0001b push ts+0x0 ; hello.c:4:1 91 | 0x0001c #printf ; hello.c:4:1 92 | 0x0001d return ; hello.c:4:1 93 | 94 | 0x0001e builtin ; hello.c:5:1 95 | 0x0001f #printf ; printf:253:1 96 | 0x00020 ffireturn ; printf:253:1 97 | 98 | Text segment 99 | 00000000 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a 00 00 00 00 |hello world.....| 100 | 101 | Data segment 102 | 00000000 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............| 103 | 00000010 38 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |8...............| 104 | 00000020 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............| 105 | 106 | DS relative bitvector 107 | 00000000 01 00 01 00 01 |.....| 108 | 109 | Symbol table 110 | 0x00012 function __builtin_exit 111 | 0x0000f function __register_stdfiles 112 | 0x00000 function _start 113 | 0x00014 function main 114 | 0x0001e function printf 115 | $ 116 | -------------------------------------------------------------------------------- /99dump/all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "path" 11 | "runtime" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func caller(s string, va ...interface{}) { 17 | if s == "" { 18 | s = strings.Repeat("%v ", len(va)) 19 | } 20 | _, fn, fl, _ := runtime.Caller(2) 21 | fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 22 | fmt.Fprintf(os.Stderr, s, va...) 23 | fmt.Fprintln(os.Stderr) 24 | _, fn, fl, _ = runtime.Caller(1) 25 | fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 26 | fmt.Fprintln(os.Stderr) 27 | os.Stderr.Sync() 28 | } 29 | 30 | func dbg(s string, va ...interface{}) { 31 | if s == "" { 32 | s = strings.Repeat("%v ", len(va)) 33 | } 34 | _, fn, fl, _ := runtime.Caller(1) 35 | fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 36 | fmt.Fprintf(os.Stderr, s, va...) 37 | fmt.Fprintln(os.Stderr) 38 | os.Stderr.Sync() 39 | } 40 | 41 | func TODO(...interface{}) string { //TODOOK 42 | _, fn, fl, _ := runtime.Caller(1) 43 | return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 44 | } 45 | 46 | func init() { 47 | use(caller, dbg, TODO) //TODOOK 48 | } 49 | 50 | // ============================================================================ 51 | 52 | func Test(t *testing.T) { 53 | t.Logf("TODO") 54 | } 55 | -------------------------------------------------------------------------------- /99dump/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Command 99dump lists object and executable files produced by the 99c compiler. 6 | // 7 | // Usage 8 | // 9 | // To dump object or binary files produced by the 99c compiler 10 | // 11 | // 99dump [files...] 12 | // 13 | // Installation 14 | // 15 | // To install or update 99dump 16 | // 17 | // $ go get [-u] github.com/cznic/99c/99dump 18 | // 19 | // Online documentation: [godoc.org/github.com/cznic/99c/99dump](http://godoc.org/github.com/cznic/99c/99dump) 20 | // 21 | // Changelog 22 | // 23 | // 2017-10-09: Initial public release. 24 | // 25 | // Sample 26 | // 27 | // Dump hello.c 28 | // 29 | // $ cd ../examples/hello/ 30 | // $ ls * 31 | // hello.c log 32 | // $ 99c -c hello.c && 99dump hello.o 33 | // ir.Objects hello.o: 34 | // # [0]: *ir.FunctionDefinition { ExternalLinkage __builtin_fopen func(*int8,*int8)*struct{} X__FILE_TYPE__ /home/jnml/src/github.com/cznic/ccir/libc/builtin.h:45:15} [__filename __modes] 35 | // 0x00000 panic ; /home/jnml/src/github.com/cznic/ccir/libc/builtin.h:45:15 36 | // # [1]: *ir.FunctionDefinition { ExternalLinkage __builtin_strlen func(*int8)uint64 /home/jnml/src/github.com/cznic/ccir/libc/builtin.h:46:15} [__s] 37 | // ... 38 | // # [62]: *ir.FunctionDefinition { ExternalLinkage main func()int32 hello.c:3:1} [] 39 | // 0x00000 result �, *int32 ; hello.c:3:12 40 | // 0x00001 const 0x0, int32 ; hello.c:3:12 41 | // 0x00002 store int32 ; hello.c:3:12 42 | // 0x00003 drop int32 ; hello.c:3:12 43 | // 0x00004 beginScope ; hello.c:3:12 44 | // 0x00005 allocResult int32 ; hello.c:4:2 45 | // 0x00006 global &printf, *func(*int8...)int32 ; hello.c:4:2 46 | // 0x00007 arguments ; hello.c:4:9 47 | // 0x00008 const "hello world\n", *int8 ; hello.c:4:9 48 | // 0x00009 callfp 1, *func(*int8...)int32 ; hello.c:4:2 49 | // 0x0000a drop int32 ; hello.c:4:2 50 | // 0x0000b return ; hello.c:5:1 51 | // 0x0000c endScope ; hello.c:5:1 52 | // # [63]: *ir.DataDefinition { InternalLinkage main__func__0 [5]int8 -} "main"+0 53 | // jnml@r550:~/src/github.com/cznic/99c/examples/hello$ 99c hello.o && 99dump a.out 54 | // virtual.Binary a.out: code 0x00021, text 0x00010, data 0x00030, bss 0x00020, pc2func 2, pc2line 10 55 | // 0x00000 call 0x2 ; - 56 | // 0x00001 ffireturn ; - 57 | // 58 | // # _start 59 | // 0x00002 func ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:13:1 60 | // 0x00003 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 61 | // 0x00004 push64 (ds) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 62 | // 0x00005 push64 (ds+0x10) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 63 | // 0x00006 push64 (ds+0x20) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 64 | // 0x00007 #register_stdfiles ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 65 | // 0x00008 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 66 | // 0x00009 sub sp, 0x8 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 67 | // 0x0000a arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 68 | // 0x0000b push32 (ap-0x8) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 69 | // 0x0000c push64 (ap-0x10) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 70 | // 0x0000d call 0x16 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 71 | // 0x0000e #exit ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 72 | // 73 | // 0x0000f builtin ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:16:1 74 | // 0x00010 #register_stdfiles ; __register_stdfiles:89:1 75 | // 0x00011 ffireturn ; __register_stdfiles:89:1 76 | // 77 | // 0x00012 add sp, 0x8 ; __builtin_exit:86:1 78 | // 0x00013 #exit ; __builtin_exit:86:1 79 | // 80 | // 0x00014 call 0x16 ; __builtin_exit:86:1 81 | // 0x00015 ffireturn ; __builtin_exit:86:1 82 | // 83 | // # main 84 | // 0x00016 func ; hello.c:3:1 85 | // 0x00017 push ap ; hello.c:3:1 86 | // 0x00018 zero32 ; hello.c:3:1 87 | // 0x00019 store32 ; hello.c:3:1 88 | // 0x0001a arguments ; hello.c:3:1 89 | // 0x0001b push ts+0x0 ; hello.c:4:1 90 | // 0x0001c #printf ; hello.c:4:1 91 | // 0x0001d return ; hello.c:4:1 92 | // 93 | // 0x0001e builtin ; hello.c:5:1 94 | // 0x0001f #printf ; printf:253:1 95 | // 0x00020 ffireturn ; printf:253:1 96 | // 97 | // Text segment 98 | // 00000000 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a 00 00 00 00 |hello world.....| 99 | // 100 | // Data segment 101 | // 00000000 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............| 102 | // 00000010 38 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |8...............| 103 | // 00000020 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............| 104 | // 105 | // DS relative bitvector 106 | // 00000000 01 00 01 00 01 |.....| 107 | // 108 | // Symbol table 109 | // 0x00012 function __builtin_exit 110 | // 0x0000f function __register_stdfiles 111 | // 0x00000 function _start 112 | // 0x00014 function main 113 | // 0x0001e function printf 114 | // $ 115 | package main 116 | 117 | import ( 118 | "bufio" 119 | "encoding/hex" 120 | "fmt" 121 | "io" 122 | "os" 123 | "path/filepath" 124 | "sort" 125 | "text/tabwriter" 126 | 127 | "github.com/cznic/ir" 128 | "github.com/cznic/virtual" 129 | "github.com/cznic/xc" 130 | ) 131 | 132 | func exit(code int, msg string, arg ...interface{}) { 133 | if msg != "" { 134 | fmt.Fprintf(os.Stderr, os.Args[0]+": "+msg, arg...) 135 | } 136 | os.Exit(code) 137 | } 138 | 139 | const ( 140 | bin = true 141 | obj = false 142 | ) 143 | 144 | func use(...interface{}) {} 145 | 146 | func main() { 147 | w := bufio.NewWriter(os.Stdout) 148 | 149 | defer w.Flush() 150 | 151 | for _, arg := range os.Args[1:] { 152 | switch { 153 | case filepath.Ext(arg) == ".o": 154 | use(try(w, arg, obj) || try(w, arg, bin) || unknown(arg)) 155 | default: 156 | use(try(w, arg, bin) || try(w, arg, obj) || unknown(arg)) 157 | } 158 | } 159 | } 160 | 161 | func unknown(fn string) bool { 162 | exit(1, "unrecognized file format: %s\n", fn) 163 | panic("unreachable") 164 | } 165 | 166 | func try(w io.Writer, fn string, bin bool) bool { 167 | tw := new(tabwriter.Writer) 168 | tw.Init(w, 0, 8, 1, '\t', 0) 169 | 170 | defer tw.Flush() 171 | 172 | w = tw 173 | f, err := os.Open(fn) 174 | if err != nil { 175 | exit(1, "%v\n", err) 176 | } 177 | 178 | r := bufio.NewReader(f) 179 | switch { 180 | case bin: 181 | var b virtual.Binary 182 | if _, err := b.ReadFrom(r); err != nil { 183 | return false 184 | } 185 | 186 | fmt.Fprintf(w, "%T %s: code %#05x, text %#05x, data %#05x, bss %#05x, pc2func %v, pc2line %v\n", 187 | b, fn, len(b.Code), len(b.Text), len(b.Data), b.BSS, len(b.Functions), len(b.Lines), 188 | ) 189 | virtual.DumpCode(w, b.Code, 0, b.Functions, b.Lines) 190 | if len(b.Text) != 0 { 191 | fmt.Fprintf(w, "Text segment\n%s\n", hex.Dump(b.Text)) 192 | } 193 | if len(b.Data) != 0 { 194 | fmt.Fprintf(w, "Data segment\n%s\n", hex.Dump(b.Data)) 195 | } 196 | if len(b.TSRelative) != 0 { 197 | fmt.Fprintf(w, "TS relative bitvector\n%s\n", hex.Dump(b.TSRelative)) 198 | } 199 | if len(b.DSRelative) != 0 { 200 | fmt.Fprintf(w, "DS relative bitvector\n%s\n", hex.Dump(b.DSRelative)) 201 | } 202 | var a []string 203 | for k := range b.Sym { 204 | a = append(a, string(xc.Dict.S(int(k)))) 205 | } 206 | sort.Strings(a) 207 | fmt.Fprintln(w, "Symbol table") 208 | for _, k := range a { 209 | fmt.Fprintf(w, "%#05x\tfunction\t%s\n", b.Sym[ir.NameID(xc.Dict.SID(k))], k) 210 | } 211 | default: 212 | var o ir.Objects 213 | if _, err := o.ReadFrom(r); err != nil { 214 | return false 215 | } 216 | 217 | fmt.Fprintf(w, "%T %s:\n", o, fn) 218 | for i, v := range o { 219 | for j, v := range v { 220 | switch x := v.(type) { 221 | case *ir.DataDefinition: 222 | fmt.Fprintf(w, "# [%v, %v]: %T %v %v\n", i, j, x, x.ObjectBase, x.Value) 223 | case *ir.FunctionDefinition: 224 | fmt.Fprintf(w, "# [%v, %v]: %T %v %v\n", i, j, x, x.ObjectBase, x.Arguments) 225 | for i, v := range x.Body { 226 | fmt.Fprintf(w, "%#05x\t%v\n", i, v) 227 | } 228 | } 229 | } 230 | } 231 | 232 | } 233 | return true 234 | } 235 | -------------------------------------------------------------------------------- /99nm/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The 99c Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | .PHONY: all clean cover cpu editor internalError later mem nuke todo edit 6 | 7 | grep=--include=*.go --include=*.l --include=*.y --include=*.yy 8 | ngrep='TODOOK\|parser\.go\|scanner\.go\|.*_string\.go' 9 | 10 | all: editor 11 | go vet 2>&1 | grep -v $(ngrep) || true 12 | golint 2>&1 | grep -v $(ngrep) || true 13 | make todo 14 | unused . || true 15 | misspell *.go 16 | gosimple || true 17 | maligned || true 18 | unconvert -apply 19 | 20 | clean: 21 | go clean 22 | rm -f *~ *.test *.out 23 | 24 | cover: 25 | t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t 26 | 27 | cpu: clean 28 | go test -run @ -bench . -cpuprofile cpu.out 29 | go tool pprof -lines *.test cpu.out 30 | 31 | edit: 32 | @ 1>/dev/null 2>/dev/null gvim -p Makefile *.go 33 | 34 | editor: 35 | gofmt -l -s -w *.go 36 | go test -i 37 | go test 2>&1 | tee log 38 | go install 39 | 40 | internalError: 41 | egrep -ho '"internal error.*"' *.go | sort | cat -n 42 | 43 | later: 44 | @grep -n $(grep) LATER * || true 45 | @grep -n $(grep) MAYBE * || true 46 | 47 | mem: clean 48 | go test -run @ -bench . -memprofile mem.out -memprofilerate 1 -timeout 24h 49 | go tool pprof -lines -web -alloc_space *.test mem.out 50 | 51 | nuke: clean 52 | go clean -i 53 | 54 | todo: 55 | @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true 56 | @grep -nr $(grep) TODO * | grep -v $(ngrep) || true 57 | @grep -nr $(grep) BUG * | grep -v $(ngrep) || true 58 | @grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true 59 | -------------------------------------------------------------------------------- /99nm/README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | 1. Usage 4 | 1. Installation 5 | 1. Changelog 6 | 1. Sample 7 | 8 | # 99nm 9 | 10 | Command 99nm lists names in object and executable files produced by the 99c compiler. 11 | 12 | ### Usage 13 | 14 | 99nm [files...] 15 | 16 | ### Installation 17 | 18 | To install or update 99nm 19 | 20 | $ go get [-u] github.com/cznic/99c/99nm 21 | 22 | Online documentation: [godoc.org/github.com/cznic/99c/99nm](http://godoc.org/github.com/cznic/99c/99nm) 23 | 24 | ### Changelog 25 | 26 | 2017-10-14: Initial public release. 27 | 28 | ### Sample 29 | 30 | $ cd ../examples/nm/ 31 | $ ls * 32 | foo.c 33 | $ cat foo.c 34 | int i; 35 | 36 | static int j; 37 | 38 | int foo() 39 | { 40 | } 41 | 42 | static int bar() 43 | { 44 | } 45 | 46 | int main() 47 | { 48 | } 49 | $ 99c foo.c -g && 99nm a.out 50 | 0x00012 __builtin_exit 51 | 0x0000f __register_stdfiles 52 | 0x00000 _start 53 | 0x00014 main 54 | $ 99c -99lib foo.c && 99nm a.out 55 | 0x00077 __builtin_abort 56 | 0x00079 __builtin_abs 57 | 0x0001b __builtin_alloca 58 | 0x0001e __builtin_bswap64 59 | 0x00021 __builtin_clrsb 60 | 0x00024 __builtin_clrsbl 61 | 0x00027 __builtin_clrsbll 62 | 0x0002a __builtin_clz 63 | 0x0002d __builtin_clzl 64 | 0x00030 __builtin_clzll 65 | 0x0005f __builtin_copysign 66 | 0x00033 __builtin_ctz 67 | 0x00036 __builtin_ctzl 68 | 0x00039 __builtin_ctzll 69 | 0x00019 __builtin_exit 70 | 0x00091 __builtin_ffs 71 | 0x00094 __builtin_ffsl 72 | 0x00097 __builtin_ffsll 73 | 0x00068 __builtin_fopen 74 | 0x0006b __builtin_fprintf 75 | 0x0003c __builtin_frame_address 76 | 0x00056 __builtin_isprint 77 | 0x00062 __builtin_longjmp 78 | 0x00074 __builtin_malloc 79 | 0x00085 __builtin_memcmp 80 | 0x0008b __builtin_memcpy 81 | 0x0007c __builtin_memset 82 | 0x0003f __builtin_parity 83 | 0x00042 __builtin_parityl 84 | 0x00045 __builtin_parityll 85 | 0x00048 __builtin_popcount 86 | 0x0004b __builtin_popcountl 87 | 0x0004e __builtin_popcountll 88 | 0x0006e __builtin_printf 89 | 0x00051 __builtin_return_address 90 | 0x00065 __builtin_setjmp 91 | 0x00071 __builtin_sprintf 92 | 0x0008e __builtin_strchr 93 | 0x0007f __builtin_strcmp 94 | 0x00082 __builtin_strcpy 95 | 0x00088 __builtin_strlen 96 | 0x00054 __builtin_trap 97 | 0x00016 __register_stdfiles 98 | 0x00059 __signbit 99 | 0x0005c __signbitf 100 | 0x00007 _start 101 | 0x0009a foo 102 | 0x00000 main 103 | $ 99c -c foo.c && 99nm foo.o 104 | __builtin_abort func() 105 | __builtin_abs func(int32)int32 106 | __builtin_alloca func(uint64)*struct{} 107 | __builtin_bswap64 func(uint64)uint64 108 | __builtin_clrsb func(int32)int32 109 | __builtin_clrsbl func(int64)int32 110 | __builtin_clrsbll func(int64)int32 111 | __builtin_clz func(uint32)int32 112 | __builtin_clzl func(uint64)int32 113 | __builtin_clzll func(uint64)int32 114 | __builtin_copysign func(float64,float64)float64 115 | __builtin_ctz func(uint32)int32 116 | __builtin_ctzl func(uint64)int32 117 | __builtin_ctzll func(uint64)int32 118 | __builtin_exit func(int32) 119 | __builtin_ffs func(int32)int32 120 | __builtin_ffsl func(int64)int32 121 | __builtin_ffsll func(int64)int32 122 | __builtin_fopen func(*int8,*int8)*struct{} 123 | __builtin_fprintf func(*struct{},*int8...)int32 124 | __builtin_frame_address func(uint32)*struct{} 125 | __builtin_isprint func(int32)int32 126 | __builtin_longjmp func(*struct{},int32) 127 | __builtin_malloc func(uint64)*struct{} 128 | __builtin_memcmp func(*struct{},*struct{},uint64)int32 129 | __builtin_memcpy func(*struct{},*struct{},uint64)*struct{} 130 | __builtin_memset func(*struct{},int32,uint64)*struct{} 131 | __builtin_parity func(uint32)int32 132 | __builtin_parityl func(uint64)int32 133 | __builtin_parityll func(uint64)int32 134 | __builtin_popcount func(uint32)int32 135 | __builtin_popcountl func(uint64)int32 136 | __builtin_popcountll func(uint64)int32 137 | __builtin_printf func(*int8...)int32 138 | __builtin_return_address func(uint32)*struct{} 139 | __builtin_setjmp func(*struct{})int32 140 | __builtin_sprintf func(*int8,*int8...)int32 141 | __builtin_strchr func(*int8,int32)*int8 142 | __builtin_strcmp func(*int8,*int8)int32 143 | __builtin_strcpy func(*int8,*int8)*int8 144 | __builtin_strlen func(*int8)uint64 145 | __builtin_trap func() 146 | __register_stdfiles func(*struct{},*struct{},*struct{}) 147 | __signbit func(float64)int32 148 | __signbitf func(float32)int32 149 | foo func()int32 150 | i int32 151 | main func()int32 152 | $ 153 | -------------------------------------------------------------------------------- /99nm/all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "path" 11 | "runtime" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func caller(s string, va ...interface{}) { 17 | if s == "" { 18 | s = strings.Repeat("%v ", len(va)) 19 | } 20 | _, fn, fl, _ := runtime.Caller(2) 21 | fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 22 | fmt.Fprintf(os.Stderr, s, va...) 23 | fmt.Fprintln(os.Stderr) 24 | _, fn, fl, _ = runtime.Caller(1) 25 | fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 26 | fmt.Fprintln(os.Stderr) 27 | os.Stderr.Sync() 28 | } 29 | 30 | func dbg(s string, va ...interface{}) { 31 | if s == "" { 32 | s = strings.Repeat("%v ", len(va)) 33 | } 34 | _, fn, fl, _ := runtime.Caller(1) 35 | fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 36 | fmt.Fprintf(os.Stderr, s, va...) 37 | fmt.Fprintln(os.Stderr) 38 | os.Stderr.Sync() 39 | } 40 | 41 | func TODO(...interface{}) string { //TODOOK 42 | _, fn, fl, _ := runtime.Caller(1) 43 | return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 44 | } 45 | 46 | func init() { 47 | use(caller, dbg, TODO) //TODOOK 48 | } 49 | 50 | // ============================================================================ 51 | 52 | func Test(t *testing.T) { 53 | t.Logf("TODO") 54 | } 55 | -------------------------------------------------------------------------------- /99nm/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Command 99nm lists names in object and executable files produced by the 99c compiler. 6 | // 7 | // Usage 8 | // 9 | // 99nm [files...] 10 | // 11 | // Installation 12 | // 13 | // To install or update 99nm 14 | // 15 | // $ go get [-u] github.com/cznic/99c/99nm 16 | // 17 | // Online documentation: [godoc.org/github.com/cznic/99c/99nm](http://godoc.org/github.com/cznic/99c/99nm) 18 | // 19 | // Changelog 20 | // 21 | // 2017-10-14: Initial public release. 22 | // 23 | // Sample 24 | // 25 | // Listing names 26 | // 27 | // $ cd ../examples/nm/ 28 | // $ ls * 29 | // foo.c 30 | // $ cat foo.c 31 | // int i; 32 | // 33 | // static int j; 34 | // 35 | // int foo() 36 | // { 37 | // } 38 | // 39 | // static int bar() 40 | // { 41 | // } 42 | // 43 | // int main() 44 | // { 45 | // } 46 | // $ 99c foo.c -g && 99nm a.out 47 | // 0x00012 __builtin_exit 48 | // 0x0000f __register_stdfiles 49 | // 0x00000 _start 50 | // 0x00014 main 51 | // $ 99c -99lib foo.c && 99nm a.out 52 | // 0x00077 __builtin_abort 53 | // 0x00079 __builtin_abs 54 | // 0x0001b __builtin_alloca 55 | // 0x0001e __builtin_bswap64 56 | // 0x00021 __builtin_clrsb 57 | // 0x00024 __builtin_clrsbl 58 | // 0x00027 __builtin_clrsbll 59 | // 0x0002a __builtin_clz 60 | // 0x0002d __builtin_clzl 61 | // 0x00030 __builtin_clzll 62 | // 0x0005f __builtin_copysign 63 | // 0x00033 __builtin_ctz 64 | // 0x00036 __builtin_ctzl 65 | // 0x00039 __builtin_ctzll 66 | // 0x00019 __builtin_exit 67 | // 0x00091 __builtin_ffs 68 | // 0x00094 __builtin_ffsl 69 | // 0x00097 __builtin_ffsll 70 | // 0x00068 __builtin_fopen 71 | // 0x0006b __builtin_fprintf 72 | // 0x0003c __builtin_frame_address 73 | // 0x00056 __builtin_isprint 74 | // 0x00062 __builtin_longjmp 75 | // 0x00074 __builtin_malloc 76 | // 0x00085 __builtin_memcmp 77 | // 0x0008b __builtin_memcpy 78 | // 0x0007c __builtin_memset 79 | // 0x0003f __builtin_parity 80 | // 0x00042 __builtin_parityl 81 | // 0x00045 __builtin_parityll 82 | // 0x00048 __builtin_popcount 83 | // 0x0004b __builtin_popcountl 84 | // 0x0004e __builtin_popcountll 85 | // 0x0006e __builtin_printf 86 | // 0x00051 __builtin_return_address 87 | // 0x00065 __builtin_setjmp 88 | // 0x00071 __builtin_sprintf 89 | // 0x0008e __builtin_strchr 90 | // 0x0007f __builtin_strcmp 91 | // 0x00082 __builtin_strcpy 92 | // 0x00088 __builtin_strlen 93 | // 0x00054 __builtin_trap 94 | // 0x00016 __register_stdfiles 95 | // 0x00059 __signbit 96 | // 0x0005c __signbitf 97 | // 0x00007 _start 98 | // 0x0009a foo 99 | // 0x00000 main 100 | // $ 99c -c foo.c && 99nm foo.o 101 | // __builtin_abort func() 102 | // __builtin_abs func(int32)int32 103 | // __builtin_alloca func(uint64)*struct{} 104 | // __builtin_bswap64 func(uint64)uint64 105 | // __builtin_clrsb func(int32)int32 106 | // __builtin_clrsbl func(int64)int32 107 | // __builtin_clrsbll func(int64)int32 108 | // __builtin_clz func(uint32)int32 109 | // __builtin_clzl func(uint64)int32 110 | // __builtin_clzll func(uint64)int32 111 | // __builtin_copysign func(float64,float64)float64 112 | // __builtin_ctz func(uint32)int32 113 | // __builtin_ctzl func(uint64)int32 114 | // __builtin_ctzll func(uint64)int32 115 | // __builtin_exit func(int32) 116 | // __builtin_ffs func(int32)int32 117 | // __builtin_ffsl func(int64)int32 118 | // __builtin_ffsll func(int64)int32 119 | // __builtin_fopen func(*int8,*int8)*struct{} 120 | // __builtin_fprintf func(*struct{},*int8...)int32 121 | // __builtin_frame_address func(uint32)*struct{} 122 | // __builtin_isprint func(int32)int32 123 | // __builtin_longjmp func(*struct{},int32) 124 | // __builtin_malloc func(uint64)*struct{} 125 | // __builtin_memcmp func(*struct{},*struct{},uint64)int32 126 | // __builtin_memcpy func(*struct{},*struct{},uint64)*struct{} 127 | // __builtin_memset func(*struct{},int32,uint64)*struct{} 128 | // __builtin_parity func(uint32)int32 129 | // __builtin_parityl func(uint64)int32 130 | // __builtin_parityll func(uint64)int32 131 | // __builtin_popcount func(uint32)int32 132 | // __builtin_popcountl func(uint64)int32 133 | // __builtin_popcountll func(uint64)int32 134 | // __builtin_printf func(*int8...)int32 135 | // __builtin_return_address func(uint32)*struct{} 136 | // __builtin_setjmp func(*struct{})int32 137 | // __builtin_sprintf func(*int8,*int8...)int32 138 | // __builtin_strchr func(*int8,int32)*int8 139 | // __builtin_strcmp func(*int8,*int8)int32 140 | // __builtin_strcpy func(*int8,*int8)*int8 141 | // __builtin_strlen func(*int8)uint64 142 | // __builtin_trap func() 143 | // __register_stdfiles func(*struct{},*struct{},*struct{}) 144 | // __signbit func(float64)int32 145 | // __signbitf func(float32)int32 146 | // foo func()int32 147 | // i int32 148 | // main func()int32 149 | // $ 150 | package main 151 | 152 | import ( 153 | "bufio" 154 | "fmt" 155 | "io" 156 | "os" 157 | "path/filepath" 158 | "sort" 159 | "text/tabwriter" 160 | 161 | "github.com/cznic/ir" 162 | "github.com/cznic/virtual" 163 | "github.com/cznic/xc" 164 | ) 165 | 166 | func exit(code int, msg string, arg ...interface{}) { 167 | if msg != "" { 168 | fmt.Fprintf(os.Stderr, os.Args[0]+": "+msg, arg...) 169 | } 170 | os.Exit(code) 171 | } 172 | 173 | const ( 174 | bin = true 175 | obj = false 176 | ) 177 | 178 | func use(...interface{}) {} 179 | 180 | func main() { 181 | w := bufio.NewWriter(os.Stdout) 182 | 183 | defer w.Flush() 184 | 185 | for _, arg := range os.Args[1:] { 186 | if len(os.Args) > 2 { 187 | fmt.Fprintf(w, "file %v\n", arg) 188 | } 189 | switch { 190 | case filepath.Ext(arg) == ".o": 191 | use(try(w, arg, obj) || try(w, arg, bin) || unknown(arg)) 192 | default: 193 | use(try(w, arg, bin) || try(w, arg, obj) || unknown(arg)) 194 | } 195 | } 196 | } 197 | 198 | func unknown(fn string) bool { 199 | exit(1, "unrecognized file format: %s\n", fn) 200 | panic("unreachable") 201 | } 202 | 203 | func try(w io.Writer, fn string, bin bool) bool { 204 | tw := new(tabwriter.Writer) 205 | tw.Init(w, 0, 8, 1, '\t', 0) 206 | 207 | defer tw.Flush() 208 | 209 | w = tw 210 | f, err := os.Open(fn) 211 | if err != nil { 212 | exit(1, "%v\n", err) 213 | } 214 | 215 | r := bufio.NewReader(f) 216 | var a []string 217 | switch { 218 | case bin: 219 | var b virtual.Binary 220 | if _, err := b.ReadFrom(r); err != nil { 221 | return false 222 | } 223 | 224 | for k := range b.Sym { 225 | a = append(a, string(xc.Dict.S(int(k)))) 226 | } 227 | sort.Strings(a) 228 | for _, k := range a { 229 | fmt.Fprintf(w, "%#05x\t%s\n", b.Sym[ir.NameID(xc.Dict.SID(k))], k) 230 | } 231 | default: 232 | var o ir.Objects 233 | if _, err := o.ReadFrom(r); err != nil { 234 | return false 235 | } 236 | 237 | for i, v := range o { 238 | if len(o) != 1 { 239 | fmt.Fprintf(w, "#%v\n", i) 240 | } 241 | a = a[:0] 242 | m := map[string][]ir.Object{} 243 | for _, v := range v { 244 | k := string(xc.Dict.S(int(v.Base().NameID))) 245 | a = append(a, k) 246 | m[k] = append(m[k], v) 247 | } 248 | sort.Strings(a) 249 | for _, k := range a { 250 | for _, v := range m[k] { 251 | if v.Base().Linkage == ir.InternalLinkage { 252 | continue 253 | } 254 | 255 | switch x := v.(type) { 256 | case *ir.DataDefinition: 257 | fmt.Fprintf(w, "%s\t%v\n", k, x.TypeID) 258 | case *ir.FunctionDefinition: 259 | fmt.Fprintf(w, "%s\t%v\n", k, x.TypeID) 260 | } 261 | } 262 | } 263 | } 264 | } 265 | return true 266 | } 267 | -------------------------------------------------------------------------------- /99prof/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The 99c Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | .PHONY: all clean cover cpu editor internalError later mem nuke todo edit 6 | 7 | grep=--include=*.go --include=*.l --include=*.y --include=*.yy 8 | ngrep='TODOOK\|parser\.go\|scanner\.go\|.*_string\.go' 9 | 10 | all: editor 11 | go vet 2>&1 | grep -v $(ngrep) || true 12 | golint 2>&1 | grep -v $(ngrep) || true 13 | make todo 14 | unused . || true 15 | misspell *.go 16 | gosimple || true 17 | maligned || true 18 | unconvert -apply 19 | 20 | clean: 21 | go clean 22 | rm -f *~ *.test *.out 23 | 24 | cover: 25 | t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t 26 | 27 | cpu: clean 28 | go test -run @ -bench . -cpuprofile cpu.out 29 | go tool pprof -lines *.test cpu.out 30 | 31 | edit: 32 | @ 1>/dev/null 2>/dev/null gvim -p Makefile *.go 33 | 34 | editor: 35 | gofmt -l -s -w *.go 36 | go test -i 37 | go test 2>&1 | tee log 38 | go install -tags virtual.profile 39 | 40 | internalError: 41 | egrep -ho '"internal error.*"' *.go | sort | cat -n 42 | 43 | later: 44 | @grep -n $(grep) LATER * || true 45 | @grep -n $(grep) MAYBE * || true 46 | 47 | mem: clean 48 | go test -run @ -bench . -memprofile mem.out -memprofilerate 1 -timeout 24h 49 | go tool pprof -lines -web -alloc_space *.test mem.out 50 | 51 | nuke: clean 52 | go clean -i 53 | 54 | todo: 55 | @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true 56 | @grep -nr $(grep) TODO * | grep -v $(ngrep) || true 57 | @grep -nr $(grep) BUG * | grep -v $(ngrep) || true 58 | @grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true 59 | -------------------------------------------------------------------------------- /99prof/README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | 1. Usage 4 | 1. Installation 5 | 1. Changelog 6 | 1. Sample 7 | 1. Bogomips 8 | 9 | # 99prof 10 | 11 | Command 99prof profiles programs produced by the 99c compiler. 12 | 13 | The profile is written to stderr. 14 | 15 | ### Usage 16 | 17 | Profile a program by issuing 18 | 19 | 99prof [-functions] [-lines] [-instructions] [-rate] a.out [arguments] 20 | 21 | -functions 22 | profile functions 23 | -instructions 24 | profile instructions 25 | -lines 26 | profile lines 27 | -rate int 28 | profile rate (default 1000) 29 | 30 | ### Installation 31 | 32 | To install or update 99prof 33 | 34 | $ go get [-u] -tags virtual.profile github.com/cznic/99c/99prof 35 | 36 | Online documentation: [godoc.org/github.com/cznic/99c/99prof](http://godoc.org/github.com/cznic/99c/99prof) 37 | 38 | ### Changelog 39 | 40 | 2017-10-09: Initial public release. 41 | 42 | ### Sample 43 | 44 | $ cd examples/prof/ 45 | /home/jnml/src/github.com/cznic/99c/examples/prof 46 | $ ls * 47 | bogomips.c fib.c 48 | $ cat fib.c 49 | #include 50 | #include 51 | 52 | int fib(int n) { 53 | switch (n) { 54 | case 0: 55 | return 0; 56 | case 1: 57 | return 1; 58 | default: 59 | return fib(n-1)+fib(n-2); 60 | } 61 | } 62 | 63 | int main(int argc, char **argv) { 64 | if (argc != 2) { 65 | return 2; 66 | } 67 | 68 | int n = atoi(argv[1]); 69 | if (n<=0 || n>40) { 70 | return 1; 71 | } 72 | 73 | printf("%i\n", fib(n)); 74 | } 75 | $ 99c fib.c -g && 99prof -functions -lines -instructions a.out 32 2>log 76 | 2178309 77 | $ cat log 78 | # [99prof -functions -lines -instructions a.out 32] 1.109159422s, 82.621 MIPS 79 | # functions 80 | fib 91639 100.00% 100.00% 81 | _start 1 0.00% 100.00% 82 | # lines 83 | fib.c:12: 52722 57.53% 57.53% 84 | fib.c:6: 14133 15.42% 72.95% 85 | fib.c:5: 7125 7.77% 80.73% 86 | fib.c:10: 6611 7.21% 87.94% 87 | fib.c:8: 4076 4.45% 92.39% 88 | fib.c:11: 3528 3.85% 96.24% 89 | fib.c:9: 2127 2.32% 98.56% 90 | fib.c:7: 1317 1.44% 100.00% 91 | /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:13: 1 0.00% 100.00% 92 | # instructions 93 | Argument32 14175 15.47% 15.47% 94 | Push32 9240 10.08% 25.55% 95 | Func 7126 7.78% 33.33% 96 | Call 7100 7.75% 41.07% 97 | Return 7084 7.73% 48.81% 98 | AddSP 7040 7.68% 56.49% 99 | SwitchI32 7019 7.66% 64.15% 100 | SubI32 7003 7.64% 71.79% 101 | Store32 7002 7.64% 79.43% 102 | AP 6972 7.61% 87.04% 103 | Arguments 6968 7.60% 94.64% 104 | AddI32 3528 3.85% 98.49% 105 | Zero32 1383 1.51% 100.00% 106 | $ 107 | 108 | ### Bogomips 109 | 110 | Let's try to estimate the VM bogomips value on an older Intel® Core™ i5-4670 CPU @ 3.40GHz × 4 machine. 111 | 112 | $ cd ../examples/prof/ 113 | $ ls * 114 | bogomips.c fib.c 115 | $ cat bogomips.c 116 | #include 117 | #include 118 | 119 | // src: https://en.wikipedia.org/wiki/BogoMips#Computation_of_BogoMIPS 120 | static void delay_loop(long loops) { 121 | long d0 = loops; 122 | do { 123 | --d0; 124 | } while (d0 >= 0); 125 | } 126 | 127 | int main(int argc, char **argv) { 128 | if (argc != 2) { 129 | return 2; 130 | } 131 | 132 | int n = atoi(argv[1]); 133 | if (n<=0) { 134 | return 1; 135 | } 136 | 137 | delay_loop(n); 138 | } 139 | $ 99c bogomips.c -g && 99prof -functions a.out 11370000 140 | # [99prof -functions a.out 11370000] 996.425292ms, 91.287 MIPS 141 | # functions 142 | delay_loop 90960 100.00% 100.00% 143 | _start 1 0.00% 100.00% 144 | $ time ./a.out 36600000 145 | 146 | real 0m1,007s 147 | user 0m1,004s 148 | sys 0m0,004s 149 | $ 150 | 151 | In both cases the program executes for ~1 second. 36600000/113700000 = 3.219 and that's the slowdown coefficient when running the binary under 99prof. The bogomips value is thus ~293 MIPS on this machine. 152 | 153 | $ 99dump a.out 154 | virtual.Binary a.out: code 0x0004d, text 0x00000, data 0x00030, bss 0x00020, pc2func 3, pc2line 23 155 | 0x00000 call 0x2 ; - 156 | 0x00001 ffireturn ; - 157 | 158 | # _start 159 | 0x00002 func ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:13:1 160 | 0x00003 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 161 | 0x00004 push64 (ds) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 162 | 0x00005 push64 (ds+0x10) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 163 | 0x00006 push64 (ds+0x20) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 164 | 0x00007 #register_stdfiles ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 165 | 0x00008 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 166 | 0x00009 sub sp, 0x8 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 167 | 0x0000a arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 168 | 0x0000b push32 (ap-0x8) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 169 | 0x0000c push64 (ap-0x10) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 170 | 0x0000d call 0x16 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 171 | 0x0000e #exit ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 172 | 173 | 0x0000f builtin ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:16:1 174 | 0x00010 #register_stdfiles ; __register_stdfiles:89:1 175 | 0x00011 ffireturn ; __register_stdfiles:89:1 176 | 177 | 0x00012 add sp, 0x8 ; __builtin_exit:86:1 178 | 0x00013 #exit ; __builtin_exit:86:1 179 | 180 | 0x00014 call 0x16 ; __builtin_exit:86:1 181 | 0x00015 ffireturn ; __builtin_exit:86:1 182 | 183 | # main 184 | 0x00016 func variables [0x8]byte ; bogomips.c:12:1 185 | 0x00017 push ap ; bogomips.c:12:1 186 | 0x00018 zero32 ; bogomips.c:12:1 187 | 0x00019 store32 ; bogomips.c:12:1 188 | 0x0001a add sp, 0x8 ; bogomips.c:12:1 189 | 0x0001b push32 (ap-0x8) ; bogomips.c:13:1 190 | 0x0001c push32 0x2 ; bogomips.c:13:1 191 | 0x0001d neqi32 ; bogomips.c:13:1 192 | 0x0001e jz 0x23 ; bogomips.c:13:1 193 | 194 | 0x0001f push ap ; bogomips.c:14:1 195 | 0x00020 push32 0x2 ; bogomips.c:14:1 196 | 0x00021 store32 ; bogomips.c:14:1 197 | 0x00022 return ; bogomips.c:14:1 198 | 199 | 0x00023 push bp-0x8 ; bogomips.c:13:1 200 | 0x00024 sub sp, 0x8 ; bogomips.c:17:1 201 | 0x00025 arguments ; bogomips.c:17:1 202 | 0x00026 push64 (ap-0x10) ; bogomips.c:17:1 203 | 0x00027 push32 0x1 ; bogomips.c:17:1 204 | 0x00028 indexi32 0x8 ; bogomips.c:17:1 205 | 0x00029 load64 0x0 ; bogomips.c:17:1 206 | 0x0002a #atoi ; bogomips.c:17:1 207 | 0x0002b store32 ; bogomips.c:17:1 208 | 0x0002c add sp, 0x8 ; bogomips.c:17:1 209 | 0x0002d push32 (bp-0x8) ; bogomips.c:18:1 210 | 0x0002e zero32 ; bogomips.c:18:1 211 | 0x0002f leqi32 ; bogomips.c:18:1 212 | 0x00030 jz 0x35 ; bogomips.c:18:1 213 | 214 | 0x00031 push ap ; bogomips.c:19:1 215 | 0x00032 push32 0x1 ; bogomips.c:19:1 216 | 0x00033 store32 ; bogomips.c:19:1 217 | 0x00034 return ; bogomips.c:19:1 218 | 219 | 0x00035 arguments ; bogomips.c:18:1 220 | 0x00036 push32 (bp-0x8) ; bogomips.c:22:1 221 | 0x00037 convi32i64 ; bogomips.c:22:1 222 | 0x00038 call 0x3f ; bogomips.c:22:1 223 | 0x00039 return ; bogomips.c:23:1 224 | 225 | 0x0003a builtin ; atoi:69:1 226 | 0x0003b #atoi ; atoi:69:1 227 | 0x0003c ffireturn ; atoi:69:1 228 | 229 | 0x0003d call 0x3f ; atoi:69:1 230 | 0x0003e ffireturn ; atoi:69:1 231 | 232 | # delay_loop 233 | 0x0003f func variables [0x8]byte ; bogomips.c:5:1 234 | 0x00040 push bp-0x8 ; bogomips.c:6:1 235 | 0x00041 push64 (ap-0x8) ; bogomips.c:6:1 236 | 0x00042 store64 ; bogomips.c:6:1 237 | 0x00043 add sp, 0x8 ; bogomips.c:6:1 238 | 0x00044 push bp-0x8 ; bogomips.c:7:1 239 | 0x00045 preinci64 0xffffffffffffffff ; bogomips.c:8:1 240 | 0x00046 add sp, 0x8 ; bogomips.c:8:1 241 | 0x00047 push64 (bp-0x8) ; bogomips.c:9:1 242 | 0x00048 zero32 ; bogomips.c:9:1 243 | 0x00049 convi32i64 ; bogomips.c:9:1 244 | 0x0004a geqi64 ; bogomips.c:9:1 245 | 0x0004b jnz 0x44 ; bogomips.c:9:1 246 | 247 | 0x0004c return ; bogomips.c:10:1 248 | 249 | Data segment 250 | 00000000 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............| 251 | 00000010 38 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |8...............| 252 | 00000020 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............| 253 | 254 | DS relative bitvector 255 | 00000000 01 00 01 00 01 |.....| 256 | 257 | Symbol table 258 | 0x00012 function __builtin_exit 259 | 0x0000f function __register_stdfiles 260 | 0x00000 function _start 261 | 0x0003a function atoi 262 | 0x00014 function main 263 | $ 264 | 265 | Alternatively, using 99dump, we can see that the loop consists of 8 instructions at addresses 0x00044-0x0004b. 36600000*8 = 292800000 confirming the estimated ~293 MIPS value. 266 | -------------------------------------------------------------------------------- /99prof/all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "path" 11 | "runtime" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func caller(s string, va ...interface{}) { 17 | if s == "" { 18 | s = strings.Repeat("%v ", len(va)) 19 | } 20 | _, fn, fl, _ := runtime.Caller(2) 21 | fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 22 | fmt.Fprintf(os.Stderr, s, va...) 23 | fmt.Fprintln(os.Stderr) 24 | _, fn, fl, _ = runtime.Caller(1) 25 | fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 26 | fmt.Fprintln(os.Stderr) 27 | os.Stderr.Sync() 28 | } 29 | 30 | func dbg(s string, va ...interface{}) { 31 | if s == "" { 32 | s = strings.Repeat("%v ", len(va)) 33 | } 34 | _, fn, fl, _ := runtime.Caller(1) 35 | fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 36 | fmt.Fprintf(os.Stderr, s, va...) 37 | fmt.Fprintln(os.Stderr) 38 | os.Stderr.Sync() 39 | } 40 | 41 | func TODO(...interface{}) string { //TODOOK 42 | _, fn, fl, _ := runtime.Caller(1) 43 | return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 44 | } 45 | 46 | func use(...interface{}) {} 47 | 48 | func init() { 49 | use(caller, dbg, TODO) //TODOOK 50 | } 51 | 52 | // ============================================================================ 53 | 54 | func Test(t *testing.T) { 55 | t.Logf("TODO") 56 | } 57 | -------------------------------------------------------------------------------- /99prof/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Command 99prof profiles programs produced by the 99c compiler. 6 | // 7 | // The profile is written to stderr. 8 | // 9 | // Usage 10 | // 11 | // Profile a program by issuing 12 | // 13 | // 99prof [-functions] [-lines] [-instructions] [-rate] a.out [arguments] 14 | // 15 | // -functions 16 | // profile functions 17 | // -instructions 18 | // profile instructions 19 | // -lines 20 | // profile lines 21 | // -rate int 22 | // profile rate (default 1000) 23 | // 24 | // Installation 25 | // 26 | // To install or update 99prof 27 | // 28 | // $ go get [-u] -tags virtual.profile github.com/cznic/99c/99prof 29 | // 30 | // Online documentation: [godoc.org/github.com/cznic/99c/99prof](http://godoc.org/github.com/cznic/99c/99prof) 31 | // 32 | // Changelog 33 | // 34 | // 2017-10-09: Initial public release. 35 | // 36 | // Sample 37 | // 38 | // Profile a fibonacci program. 39 | // 40 | // $ cd examples/prof/ 41 | // /home/jnml/src/github.com/cznic/99c/examples/prof 42 | // $ ls * 43 | // bogomips.c fib.c 44 | // $ cat fib.c 45 | // #include 46 | // #include 47 | // 48 | // int fib(int n) { 49 | // switch (n) { 50 | // case 0: 51 | // return 0; 52 | // case 1: 53 | // return 1; 54 | // default: 55 | // return fib(n-1)+fib(n-2); 56 | // } 57 | // } 58 | // 59 | // int main(int argc, char **argv) { 60 | // if (argc != 2) { 61 | // return 2; 62 | // } 63 | // 64 | // int n = atoi(argv[1]); 65 | // if (n<=0 || n>40) { 66 | // return 1; 67 | // } 68 | // 69 | // printf("%i\n", fib(n)); 70 | // } 71 | // $ 99c fib.c -g && 99prof -functions -lines -instructions a.out 32 2>log 72 | // 2178309 73 | // $ cat log 74 | // # [99prof -functions -lines -instructions a.out 32] 1.109159422s, 82.621 MIPS 75 | // # functions 76 | // fib 91639 100.00% 100.00% 77 | // _start 1 0.00% 100.00% 78 | // # lines 79 | // fib.c:12: 52722 57.53% 57.53% 80 | // fib.c:6: 14133 15.42% 72.95% 81 | // fib.c:5: 7125 7.77% 80.73% 82 | // fib.c:10: 6611 7.21% 87.94% 83 | // fib.c:8: 4076 4.45% 92.39% 84 | // fib.c:11: 3528 3.85% 96.24% 85 | // fib.c:9: 2127 2.32% 98.56% 86 | // fib.c:7: 1317 1.44% 100.00% 87 | // /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:13: 1 0.00% 100.00% 88 | // # instructions 89 | // Argument32 14175 15.47% 15.47% 90 | // Push32 9240 10.08% 25.55% 91 | // Func 7126 7.78% 33.33% 92 | // Call 7100 7.75% 41.07% 93 | // Return 7084 7.73% 48.81% 94 | // AddSP 7040 7.68% 56.49% 95 | // SwitchI32 7019 7.66% 64.15% 96 | // SubI32 7003 7.64% 71.79% 97 | // Store32 7002 7.64% 79.43% 98 | // AP 6972 7.61% 87.04% 99 | // Arguments 6968 7.60% 94.64% 100 | // AddI32 3528 3.85% 98.49% 101 | // Zero32 1383 1.51% 100.00% 102 | // $ 103 | // 104 | // Bogomips 105 | // 106 | // Let's try to estimate the VM bogomips value on an older Intel® Core™ i5-4670 CPU @ 3.40GHz × 4 machine. 107 | // 108 | // $ cd ../examples/prof/ 109 | // $ ls * 110 | // bogomips.c fib.c 111 | // $ cat bogomips.c 112 | // #include 113 | // #include 114 | // 115 | // // src: https://en.wikipedia.org/wiki/BogoMips#Computation_of_BogoMIPS 116 | // static void delay_loop(long loops) { 117 | // long d0 = loops; 118 | // do { 119 | // --d0; 120 | // } while (d0 >= 0); 121 | // } 122 | // 123 | // int main(int argc, char **argv) { 124 | // if (argc != 2) { 125 | // return 2; 126 | // } 127 | // 128 | // int n = atoi(argv[1]); 129 | // if (n<=0) { 130 | // return 1; 131 | // } 132 | // 133 | // delay_loop(n); 134 | // } 135 | // $ 99c bogomips.c -g && 99prof -functions a.out 11370000 136 | // # [99prof -functions a.out 11370000] 996.425292ms, 91.287 MIPS 137 | // # functions 138 | // delay_loop 90960 100.00% 100.00% 139 | // _start 1 0.00% 100.00% 140 | // $ time ./a.out 36600000 141 | // 142 | // real 0m1,007s 143 | // user 0m1,004s 144 | // sys 0m0,004s 145 | // $ 146 | // 147 | // In both cases the program executes for ~1 second. 36600000/113700000 = 3.219 and that's the slowdown coefficient when running the binary under 99prof. The bogomips value is thus ~293 MIPS on this machine. 148 | // 149 | // $ 99dump a.out 150 | // virtual.Binary a.out: code 0x0004d, text 0x00000, data 0x00030, bss 0x00020, pc2func 3, pc2line 23 151 | // 0x00000 call 0x2 ; - 152 | // 0x00001 ffireturn ; - 153 | // 154 | // # _start 155 | // 0x00002 func ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:13:1 156 | // 0x00003 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 157 | // 0x00004 push64 (ds) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 158 | // 0x00005 push64 (ds+0x10) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 159 | // 0x00006 push64 (ds+0x20) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 160 | // 0x00007 #register_stdfiles ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 161 | // 0x00008 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 162 | // 0x00009 sub sp, 0x8 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 163 | // 0x0000a arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 164 | // 0x0000b push32 (ap-0x8) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 165 | // 0x0000c push64 (ap-0x10) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 166 | // 0x0000d call 0x16 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 167 | // 0x0000e #exit ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 168 | // 169 | // 0x0000f builtin ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:16:1 170 | // 0x00010 #register_stdfiles ; __register_stdfiles:89:1 171 | // 0x00011 ffireturn ; __register_stdfiles:89:1 172 | // 173 | // 0x00012 add sp, 0x8 ; __builtin_exit:86:1 174 | // 0x00013 #exit ; __builtin_exit:86:1 175 | // 176 | // 0x00014 call 0x16 ; __builtin_exit:86:1 177 | // 0x00015 ffireturn ; __builtin_exit:86:1 178 | // 179 | // # main 180 | // 0x00016 func variables [0x8]byte ; bogomips.c:12:1 181 | // 0x00017 push ap ; bogomips.c:12:1 182 | // 0x00018 zero32 ; bogomips.c:12:1 183 | // 0x00019 store32 ; bogomips.c:12:1 184 | // 0x0001a add sp, 0x8 ; bogomips.c:12:1 185 | // 0x0001b push32 (ap-0x8) ; bogomips.c:13:1 186 | // 0x0001c push32 0x2 ; bogomips.c:13:1 187 | // 0x0001d neqi32 ; bogomips.c:13:1 188 | // 0x0001e jz 0x23 ; bogomips.c:13:1 189 | // 190 | // 0x0001f push ap ; bogomips.c:14:1 191 | // 0x00020 push32 0x2 ; bogomips.c:14:1 192 | // 0x00021 store32 ; bogomips.c:14:1 193 | // 0x00022 return ; bogomips.c:14:1 194 | // 195 | // 0x00023 push bp-0x8 ; bogomips.c:13:1 196 | // 0x00024 sub sp, 0x8 ; bogomips.c:17:1 197 | // 0x00025 arguments ; bogomips.c:17:1 198 | // 0x00026 push64 (ap-0x10) ; bogomips.c:17:1 199 | // 0x00027 push32 0x1 ; bogomips.c:17:1 200 | // 0x00028 indexi32 0x8 ; bogomips.c:17:1 201 | // 0x00029 load64 0x0 ; bogomips.c:17:1 202 | // 0x0002a #atoi ; bogomips.c:17:1 203 | // 0x0002b store32 ; bogomips.c:17:1 204 | // 0x0002c add sp, 0x8 ; bogomips.c:17:1 205 | // 0x0002d push32 (bp-0x8) ; bogomips.c:18:1 206 | // 0x0002e zero32 ; bogomips.c:18:1 207 | // 0x0002f leqi32 ; bogomips.c:18:1 208 | // 0x00030 jz 0x35 ; bogomips.c:18:1 209 | // 210 | // 0x00031 push ap ; bogomips.c:19:1 211 | // 0x00032 push32 0x1 ; bogomips.c:19:1 212 | // 0x00033 store32 ; bogomips.c:19:1 213 | // 0x00034 return ; bogomips.c:19:1 214 | // 215 | // 0x00035 arguments ; bogomips.c:18:1 216 | // 0x00036 push32 (bp-0x8) ; bogomips.c:22:1 217 | // 0x00037 convi32i64 ; bogomips.c:22:1 218 | // 0x00038 call 0x3f ; bogomips.c:22:1 219 | // 0x00039 return ; bogomips.c:23:1 220 | // 221 | // 0x0003a builtin ; atoi:69:1 222 | // 0x0003b #atoi ; atoi:69:1 223 | // 0x0003c ffireturn ; atoi:69:1 224 | // 225 | // 0x0003d call 0x3f ; atoi:69:1 226 | // 0x0003e ffireturn ; atoi:69:1 227 | // 228 | // # delay_loop 229 | // 0x0003f func variables [0x8]byte ; bogomips.c:5:1 230 | // 0x00040 push bp-0x8 ; bogomips.c:6:1 231 | // 0x00041 push64 (ap-0x8) ; bogomips.c:6:1 232 | // 0x00042 store64 ; bogomips.c:6:1 233 | // 0x00043 add sp, 0x8 ; bogomips.c:6:1 234 | // 0x00044 push bp-0x8 ; bogomips.c:7:1 235 | // 0x00045 preinci64 0xffffffffffffffff ; bogomips.c:8:1 236 | // 0x00046 add sp, 0x8 ; bogomips.c:8:1 237 | // 0x00047 push64 (bp-0x8) ; bogomips.c:9:1 238 | // 0x00048 zero32 ; bogomips.c:9:1 239 | // 0x00049 convi32i64 ; bogomips.c:9:1 240 | // 0x0004a geqi64 ; bogomips.c:9:1 241 | // 0x0004b jnz 0x44 ; bogomips.c:9:1 242 | // 243 | // 0x0004c return ; bogomips.c:10:1 244 | // 245 | // Data segment 246 | // 00000000 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............| 247 | // 00000010 38 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |8...............| 248 | // 00000020 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............| 249 | // 250 | // DS relative bitvector 251 | // 00000000 01 00 01 00 01 |.....| 252 | // 253 | // Symbol table 254 | // 0x00012 function __builtin_exit 255 | // 0x0000f function __register_stdfiles 256 | // 0x00000 function _start 257 | // 0x0003a function atoi 258 | // 0x00014 function main 259 | // $ 260 | // 261 | // Alternatively, using 99dump, we can see that the loop consists of 8 instructions at addresses 0x00044-0x0004b. 36600000*8 = 292800000 confirming the estimated ~293 MIPS value. 262 | package main 263 | 264 | import ( 265 | "bufio" 266 | "flag" 267 | "fmt" 268 | "io" 269 | "os" 270 | "sort" 271 | "time" 272 | 273 | "github.com/cznic/virtual" 274 | ) 275 | 276 | func exit(code int, msg string, arg ...interface{}) { 277 | if msg != "" { 278 | fmt.Fprintf(os.Stderr, os.Args[0]+": "+msg, arg...) 279 | } 280 | os.Exit(code) 281 | } 282 | 283 | func main() { 284 | if !profile { 285 | exit(1, `This tool must be built using '-tags virtual.profile', please rebuild it. 286 | Use 287 | $ go install -tags virtual.profile github.com/cznic/99c/99prof 288 | or 289 | $ go get [-u] -tags virtual.profile github.com/cznic/99c/99prof 290 | `) 291 | } 292 | 293 | functions := flag.Bool("functions", false, "profile functions") 294 | instructions := flag.Bool("instructions", false, "profile instructions") 295 | lines := flag.Bool("lines", false, "profile lines") 296 | rate := flag.Int("rate", 1000, "profile rate") 297 | flag.Parse() 298 | 299 | if flag.NArg() == 0 { 300 | exit(2, "missing program name %v\n", os.Args) 301 | } 302 | 303 | nm := flag.Arg(0) 304 | bin, err := os.Open(nm) 305 | if err != nil { 306 | exit(1, "%v\n", err) 307 | } 308 | 309 | var b virtual.Binary 310 | if _, err := b.ReadFrom(bufio.NewReader(bin)); err != nil { 311 | exit(1, "%v\n", err) 312 | } 313 | 314 | args := os.Args[1:] 315 | for i, v := range args { 316 | if v == nm { 317 | args = args[i:] 318 | break 319 | } 320 | } 321 | 322 | var opts []virtual.Option 323 | if *functions { 324 | opts = append(opts, virtual.ProfileFunctions()) 325 | } 326 | if *lines { 327 | opts = append(opts, virtual.ProfileLines()) 328 | } 329 | if *instructions { 330 | opts = append(opts, virtual.ProfileInstructions()) 331 | } 332 | if n := *rate; n != 0 { 333 | opts = append(opts, virtual.ProfileRate(n)) 334 | } 335 | 336 | t0 := time.Now() 337 | vm, code, err := virtual.New(&b, args, os.Stdin, os.Stdout, os.Stderr, 0, 8<<20, "", opts...) 338 | d := time.Since(t0) 339 | if err != nil { 340 | if code == 0 { 341 | code = 1 342 | } 343 | exit(code, "%v\n", err) 344 | } 345 | 346 | var s int64 347 | switch { 348 | case len(vm.ProfileFunctions) != 0: 349 | for _, v := range vm.ProfileFunctions { 350 | s += int64(v) 351 | } 352 | case len(vm.ProfileLines) != 0: 353 | for _, v := range vm.ProfileLines { 354 | s += int64(v) 355 | } 356 | case len(vm.ProfileInstructions) != 0: 357 | for _, v := range vm.ProfileInstructions { 358 | s += int64(v) 359 | } 360 | } 361 | if s != 0 { 362 | w := bufio.NewWriter(os.Stderr) 363 | fmt.Fprintf(w, "# %v %v, %.3f MIPS\n", os.Args, d, float64(s)/1e6*float64(*rate)*float64(time.Second)/float64(d)) 364 | out(w, vm) 365 | w.Flush() 366 | os.Stderr.Sync() 367 | } 368 | exit(code, "") 369 | } 370 | 371 | func out(w io.Writer, vm *virtual.Machine) { 372 | rate := vm.ProfileRate 373 | if rate == 0 { 374 | rate = 1 375 | } 376 | if len(vm.ProfileFunctions) != 0 { 377 | type u struct { 378 | virtual.PCInfo 379 | n int 380 | } 381 | var s int64 382 | var a []u 383 | var wi int 384 | for k, v := range vm.ProfileFunctions { 385 | a = append(a, u{k, v}) 386 | s += int64(v) 387 | if n := len(k.Name.String()); n > wi { 388 | wi = n 389 | } 390 | } 391 | sort.Slice(a, func(i, j int) bool { 392 | if a[i].n < a[j].n { 393 | return true 394 | } 395 | 396 | if a[i].n > a[j].n { 397 | return false 398 | } 399 | 400 | return a[i].Name < a[j].Name 401 | }) 402 | fmt.Fprintln(w, "# functions") 403 | var c int64 404 | for i := len(a) - 1; i >= 0; i-- { 405 | c += int64(a[i].n) 406 | fmt.Fprintf( 407 | w, 408 | "%*v\t%10v%10.2f%%%10.2f%%\n", 409 | -wi, a[i].Name, a[i].n, 410 | 100*float64(a[i].n)/float64(s), 411 | 100*float64(c)/float64(s), 412 | ) 413 | } 414 | } 415 | if len(vm.ProfileLines) != 0 { 416 | type u struct { 417 | virtual.PCInfo 418 | n int 419 | } 420 | var s int64 421 | var a []u 422 | for k, v := range vm.ProfileLines { 423 | a = append(a, u{k, v}) 424 | s += int64(v) 425 | } 426 | sort.Slice(a, func(i, j int) bool { 427 | if a[i].n < a[j].n { 428 | return true 429 | } 430 | 431 | if a[i].n > a[j].n { 432 | return false 433 | } 434 | 435 | if a[i].Name < a[j].Name { 436 | return true 437 | } 438 | 439 | if a[i].Name > a[j].Name { 440 | return false 441 | } 442 | 443 | return a[i].Line < a[j].Line 444 | }) 445 | fmt.Fprintln(w, "# lines") 446 | var c int64 447 | for i := len(a) - 1; i >= 0; i-- { 448 | c += int64(a[i].n) 449 | fmt.Fprintf( 450 | w, 451 | "%v:%v:\t%10v%10.2f%%%10.2f%%\n", 452 | a[i].Name, a[i].Line, a[i].n, 453 | 100*float64(a[i].n)/float64(s), 454 | 100*float64(c)/float64(s), 455 | ) 456 | } 457 | } 458 | if len(vm.ProfileInstructions) != 0 { 459 | type u struct { 460 | virtual.Opcode 461 | n int 462 | } 463 | var s int64 464 | var a []u 465 | var wi int 466 | for k, v := range vm.ProfileInstructions { 467 | a = append(a, u{k, v}) 468 | s += int64(v) 469 | if n := len(k.String()); n > wi { 470 | wi = n 471 | } 472 | } 473 | sort.Slice(a, func(i, j int) bool { 474 | if a[i].n < a[j].n { 475 | return true 476 | } 477 | 478 | if a[i].n > a[j].n { 479 | return false 480 | } 481 | 482 | return a[i].Opcode < a[j].Opcode 483 | }) 484 | fmt.Fprintln(w, "# instructions") 485 | var c int64 486 | for i := len(a) - 1; i >= 0; i-- { 487 | c += int64(a[i].n) 488 | fmt.Fprintf( 489 | w, 490 | "%*s%10v%10.2f%%\t%10.2f%%\n", 491 | -wi, a[i].Opcode, a[i].n, 492 | 100*float64(a[i].n)/float64(s), 493 | 100*float64(c)/float64(s), 494 | ) 495 | } 496 | } 497 | } 498 | -------------------------------------------------------------------------------- /99prof/profile_disabled.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !virtual.profile 6 | 7 | package main 8 | 9 | const profile = false 10 | -------------------------------------------------------------------------------- /99prof/profile_enabled.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build virtual.profile 6 | 7 | package main 8 | 9 | const profile = true 10 | -------------------------------------------------------------------------------- /99run/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The 99c Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | .PHONY: all clean cover cpu editor internalError later mem nuke todo edit 6 | 7 | grep=--include=*.go --include=*.l --include=*.y --include=*.yy 8 | ngrep='TODOOK\|parser\.go\|scanner\.go\|.*_string\.go' 9 | 10 | all: editor 11 | go vet 2>&1 | grep -v $(ngrep) || true 12 | golint 2>&1 | grep -v $(ngrep) || true 13 | make todo 14 | unused . || true 15 | misspell *.go 16 | gosimple || true 17 | maligned || true 18 | unconvert -apply 19 | 20 | clean: 21 | go clean 22 | rm -f *~ *.test *.out 23 | 24 | cover: 25 | t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t 26 | 27 | cpu: clean 28 | go test -run @ -bench . -cpuprofile cpu.out 29 | go tool pprof -lines *.test cpu.out 30 | 31 | edit: 32 | @ 1>/dev/null 2>/dev/null gvim -p Makefile *.go 33 | 34 | editor: 35 | gofmt -l -s -w *.go 36 | go test -i 37 | go test 2>&1 | tee log 38 | go install 39 | 40 | internalError: 41 | egrep -ho '"internal error.*"' *.go | sort | cat -n 42 | 43 | later: 44 | @grep -n $(grep) LATER * || true 45 | @grep -n $(grep) MAYBE * || true 46 | 47 | mem: clean 48 | go test -run @ -bench . -memprofile mem.out -memprofilerate 1 -timeout 24h 49 | go tool pprof -lines -web -alloc_space *.test mem.out 50 | 51 | nuke: clean 52 | go clean -i 53 | 54 | todo: 55 | @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true 56 | @grep -nr $(grep) TODO * | grep -v $(ngrep) || true 57 | @grep -nr $(grep) BUG * | grep -v $(ngrep) || true 58 | @grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true 59 | -------------------------------------------------------------------------------- /99run/README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | 1. Usage 4 | 1. Installation 5 | 1. Changelog 6 | 7 | # 99run 8 | 9 | Command 99run executes binary programs produced by the 99c compiler. 10 | 11 | ### Usage 12 | 13 | 99run a.out 14 | 15 | On Linux a.out can be executed directly. 16 | 17 | ### Installation 18 | 19 | To install or update 99run 20 | 21 | $ go get [-u] github.com/cznic/99c/99run 22 | 23 | Online documentation: [godoc.org/github.com/cznic/99c/99run](http://godoc.org/github.com/cznic/99c/99run) 24 | 25 | ### Changelog 26 | 27 | 2017-10-07: Initial public release. 28 | -------------------------------------------------------------------------------- /99run/all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "path" 11 | "runtime" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func caller(s string, va ...interface{}) { 17 | if s == "" { 18 | s = strings.Repeat("%v ", len(va)) 19 | } 20 | _, fn, fl, _ := runtime.Caller(2) 21 | fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 22 | fmt.Fprintf(os.Stderr, s, va...) 23 | fmt.Fprintln(os.Stderr) 24 | _, fn, fl, _ = runtime.Caller(1) 25 | fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 26 | fmt.Fprintln(os.Stderr) 27 | os.Stderr.Sync() 28 | } 29 | 30 | func dbg(s string, va ...interface{}) { 31 | if s == "" { 32 | s = strings.Repeat("%v ", len(va)) 33 | } 34 | _, fn, fl, _ := runtime.Caller(1) 35 | fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 36 | fmt.Fprintf(os.Stderr, s, va...) 37 | fmt.Fprintln(os.Stderr) 38 | os.Stderr.Sync() 39 | } 40 | 41 | func TODO(...interface{}) string { //TODOOK 42 | _, fn, fl, _ := runtime.Caller(1) 43 | return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 44 | } 45 | 46 | func use(...interface{}) {} 47 | 48 | func init() { 49 | use(caller, dbg, TODO) //TODOOK 50 | } 51 | 52 | // ============================================================================ 53 | 54 | func Test(t *testing.T) { 55 | t.Logf("TODO") 56 | } 57 | -------------------------------------------------------------------------------- /99run/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Command 99run executes binary programs produced by the 99c compiler. 6 | // 7 | // Usage 8 | // 9 | // To execute a compiled binary named a.out 10 | // 11 | // 99run a.out [arguments] 12 | // 13 | // Installation 14 | // 15 | // To install or update 16 | // 17 | // $ go get [-u] github.com/cznic/99c/99run 18 | // 19 | // Online documentation: [godoc.org/github.com/cznic/99c/99run](http://godoc.org/github.com/cznic/99c/99run) 20 | // 21 | // Changelog 22 | // 23 | // 2017-01-07: Initial public release. 24 | package main 25 | 26 | import ( 27 | "bufio" 28 | "fmt" 29 | "os" 30 | 31 | "github.com/cznic/virtual" 32 | ) 33 | 34 | func exit(code int, msg string, arg ...interface{}) { 35 | if msg != "" { 36 | fmt.Fprintf(os.Stderr, os.Args[0]+": "+msg, arg...) 37 | } 38 | os.Exit(code) 39 | } 40 | 41 | func main() { 42 | if len(os.Args) < 2 { 43 | exit(2, "invalid arguments %v\n", os.Args) 44 | } 45 | 46 | bin, err := os.Open(os.Args[1]) 47 | if err != nil { 48 | exit(1, "%v\n", err) 49 | } 50 | 51 | var b virtual.Binary 52 | if _, err := b.ReadFrom(bufio.NewReader(bin)); err != nil { 53 | exit(1, "%v\n", err) 54 | } 55 | 56 | code, err := virtual.Exec(&b, os.Args[1:], os.Stdin, os.Stdout, os.Stderr, 0, 8<<20, "") 57 | if err != nil { 58 | if code == 0 { 59 | code = 1 60 | } 61 | exit(code, "%v\n", err) 62 | } 63 | 64 | exit(code, "") 65 | } 66 | -------------------------------------------------------------------------------- /99strace/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The 99c Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | .PHONY: all clean cover cpu editor internalError later mem nuke todo edit 6 | 7 | grep=--include=*.go --include=*.l --include=*.y --include=*.yy 8 | ngrep='TODOOK\|parser\.go\|scanner\.go\|.*_string\.go' 9 | 10 | all: editor 11 | go vet 2>&1 | grep -v $(ngrep) || true 12 | golint 2>&1 | grep -v $(ngrep) || true 13 | make todo 14 | unused . || true 15 | misspell *.go 16 | gosimple || true 17 | maligned || true 18 | unconvert -apply 19 | 20 | clean: 21 | go clean 22 | rm -f *~ *.test *.out 23 | 24 | cover: 25 | t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t 26 | 27 | cpu: clean 28 | go test -run @ -bench . -cpuprofile cpu.out 29 | go tool pprof -lines *.test cpu.out 30 | 31 | edit: 32 | @ 1>/dev/null 2>/dev/null gvim -p Makefile *.go 33 | 34 | editor: 35 | gofmt -l -s -w *.go 36 | go test -i 37 | go test 2>&1 | tee log 38 | go install -tags virtual.strace 39 | 40 | internalError: 41 | egrep -ho '"internal error.*"' *.go | sort | cat -n 42 | 43 | later: 44 | @grep -n $(grep) LATER * || true 45 | @grep -n $(grep) MAYBE * || true 46 | 47 | mem: clean 48 | go test -run @ -bench . -memprofile mem.out -memprofilerate 1 -timeout 24h 49 | go tool pprof -lines -web -alloc_space *.test mem.out 50 | 51 | nuke: clean 52 | go clean -i 53 | 54 | todo: 55 | @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true 56 | @grep -nr $(grep) TODO * | grep -v $(ngrep) || true 57 | @grep -nr $(grep) BUG * | grep -v $(ngrep) || true 58 | @grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true 59 | -------------------------------------------------------------------------------- /99strace/README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | 1. Usage 4 | 1. Installation 5 | 1. Changelog 6 | 1. Sample 7 | 8 | # 99strace 9 | 10 | Command 99strace traces system calls of programs produced by the 99c compiler. 11 | 12 | The trace is written to stderr. 13 | 14 | ### Usage 15 | 16 | 99strace a.out [arguments] 17 | 18 | ### Installation 19 | 20 | To install or update 99strace 21 | 22 | $ go get [-u] -tags virtual.strace github.com/cznic/99c/99strace 23 | 24 | Online documentation: [godoc.org/github.com/cznic/99c/99strace](http://godoc.org/github.com/cznic/99c/99strace) 25 | 26 | ### Changelog 27 | 28 | 2017-10-09: Initial public release. 29 | 30 | ### Sample 31 | 32 | $ cd ../examples/strace/ 33 | $ ls * 34 | data.txt main.c 35 | $ cat main.c 36 | #include 37 | #include 38 | #include 39 | 40 | #define BUFSIZE 1<<16 41 | 42 | int main(int argc, char **argv) { 43 | char *buf = malloc(BUFSIZE); 44 | if (!buf) { 45 | return 1; 46 | } 47 | 48 | for (int i = 1; i < argc; i++) { 49 | int fd = open(argv[i], O_RDWR); 50 | if (fd < 0) { 51 | return 1; 52 | } 53 | 54 | ssize_t n; 55 | while ((n = read(fd, buf, BUFSIZE)) > 0) { 56 | write(0, buf, n); 57 | } 58 | } 59 | free(buf); 60 | } 61 | $ cat data.txt 62 | Lorem ipsum. 63 | $ 99c main.c && ./a.out data.txt 64 | Lorem ipsum. 65 | $ 99strace a.out data.txt 66 | malloc(0x10000) 0x7f83a9400020 67 | open("data.txt", O_RDWR, 0) 5 errno 0 68 | read(5, 0x7f83a9400020, 65536) 13 errno 0 69 | Lorem ipsum. 70 | write(0, 0x7f83a9400020, 13) 13 errno 0 71 | read(5, 0x7f83a9400020, 65536) 0 errno 0 72 | freep(0x7f83a9400020) 73 | $ 74 | -------------------------------------------------------------------------------- /99strace/all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "path" 11 | "runtime" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func caller(s string, va ...interface{}) { 17 | if s == "" { 18 | s = strings.Repeat("%v ", len(va)) 19 | } 20 | _, fn, fl, _ := runtime.Caller(2) 21 | fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 22 | fmt.Fprintf(os.Stderr, s, va...) 23 | fmt.Fprintln(os.Stderr) 24 | _, fn, fl, _ = runtime.Caller(1) 25 | fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 26 | fmt.Fprintln(os.Stderr) 27 | os.Stderr.Sync() 28 | } 29 | 30 | func dbg(s string, va ...interface{}) { 31 | if s == "" { 32 | s = strings.Repeat("%v ", len(va)) 33 | } 34 | _, fn, fl, _ := runtime.Caller(1) 35 | fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 36 | fmt.Fprintf(os.Stderr, s, va...) 37 | fmt.Fprintln(os.Stderr) 38 | os.Stderr.Sync() 39 | } 40 | 41 | func TODO(...interface{}) string { //TODOOK 42 | _, fn, fl, _ := runtime.Caller(1) 43 | return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 44 | } 45 | 46 | func use(...interface{}) {} 47 | 48 | func init() { 49 | use(caller, dbg, TODO) //TODOOK 50 | } 51 | 52 | // ============================================================================ 53 | 54 | func Test(t *testing.T) { 55 | t.Logf("TODO") 56 | } 57 | -------------------------------------------------------------------------------- /99strace/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Command 99strace traces system calls of programs produced by the 99c compiler. 6 | // 7 | // The trace is written to stderr. 8 | // 9 | // Usage 10 | // 11 | // To trace a.out 12 | // 13 | // 99strace a.out [arguments] 14 | // 15 | // Installation 16 | // 17 | // To install or update 99strace 18 | // 19 | // $ go get [-u] -tags virtual.strace github.com/cznic/99c/99strace 20 | // 21 | // Online documentation: [godoc.org/github.com/cznic/99c/99strace](http://godoc.org/github.com/cznic/99c/99strace) 22 | // 23 | // Changelog 24 | // 25 | // 2017-10-09: Initial public release. 26 | // 27 | // Sample 28 | // 29 | // Example session 30 | // 31 | // $ cd ../examples/strace/ 32 | // $ ls * 33 | // data.txt main.c 34 | // $ cat main.c 35 | // #include 36 | // #include 37 | // #include 38 | // 39 | // #define BUFSIZE 1<<16 40 | // 41 | // int main(int argc, char **argv) { 42 | // char *buf = malloc(BUFSIZE); 43 | // if (!buf) { 44 | // return 1; 45 | // } 46 | // 47 | // for (int i = 1; i < argc; i++) { 48 | // int fd = open(argv[i], O_RDWR); 49 | // if (fd < 0) { 50 | // return 1; 51 | // } 52 | // 53 | // ssize_t n; 54 | // while ((n = read(fd, buf, BUFSIZE)) > 0) { 55 | // write(0, buf, n); 56 | // } 57 | // } 58 | // free(buf); 59 | // } 60 | // $ cat data.txt 61 | // Lorem ipsum. 62 | // $ 99c main.c && ./a.out data.txt 63 | // Lorem ipsum. 64 | // $ 99strace a.out data.txt 65 | // malloc(0x10000) 0x7f83a9400020 66 | // open("data.txt", O_RDWR, 0) 5 errno 0 67 | // read(5, 0x7f83a9400020, 65536) 13 errno 0 68 | // Lorem ipsum. 69 | // write(0, 0x7f83a9400020, 13) 13 errno 0 70 | // read(5, 0x7f83a9400020, 65536) 0 errno 0 71 | // freep(0x7f83a9400020) 72 | // $ 73 | package main 74 | 75 | import ( 76 | "bufio" 77 | "fmt" 78 | "os" 79 | 80 | "github.com/cznic/virtual" 81 | ) 82 | 83 | func exit(code int, msg string, arg ...interface{}) { 84 | if msg != "" { 85 | fmt.Fprintf(os.Stderr, os.Args[0]+": "+msg, arg...) 86 | } 87 | os.Exit(code) 88 | } 89 | 90 | func main() { 91 | if !strace { 92 | exit(1, `This tool must be built using '-tags virtual.strace', please rebuild it. 93 | Use 94 | $ go install -tags virtual.strace github.com/cznic/99c/99strace 95 | or 96 | $ go get [-u] -tags virtual.strace github.com/cznic/99c/99strace 97 | `) 98 | } 99 | 100 | if len(os.Args) < 2 { 101 | exit(2, "invalid arguments %v\n", os.Args) 102 | } 103 | 104 | bin, err := os.Open(os.Args[1]) 105 | if err != nil { 106 | exit(1, "%v\n", err) 107 | } 108 | 109 | var b virtual.Binary 110 | if _, err := b.ReadFrom(bufio.NewReader(bin)); err != nil { 111 | exit(1, "%v\n", err) 112 | } 113 | 114 | code, err := virtual.Exec(&b, os.Args[1:], os.Stdin, os.Stdout, os.Stderr, 0, 8<<20, "") 115 | if err != nil { 116 | if code == 0 { 117 | code = 1 118 | } 119 | exit(code, "%v\n", err) 120 | } 121 | 122 | exit(code, "") 123 | } 124 | -------------------------------------------------------------------------------- /99strace/strace_disabled.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !virtual.strace 6 | 7 | package main 8 | 9 | const strace = false 10 | -------------------------------------------------------------------------------- /99strace/strace_enabled.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build virtual.strace 6 | 7 | package main 8 | 9 | const strace = true 10 | -------------------------------------------------------------------------------- /99trace/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The 99c Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | .PHONY: all clean cover cpu editor internalError later mem nuke todo edit 6 | 7 | grep=--include=*.go --include=*.l --include=*.y --include=*.yy 8 | ngrep='TODOOK\|parser\.go\|scanner\.go\|.*_string\.go' 9 | 10 | all: editor 11 | go vet 2>&1 | grep -v $(ngrep) || true 12 | golint 2>&1 | grep -v $(ngrep) || true 13 | make todo 14 | unused . || true 15 | misspell *.go 16 | gosimple || true 17 | maligned || true 18 | unconvert -apply 19 | 20 | clean: 21 | go clean 22 | rm -f *~ *.test *.out 23 | 24 | cover: 25 | t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t 26 | 27 | cpu: clean 28 | go test -run @ -bench . -cpuprofile cpu.out 29 | go tool pprof -lines *.test cpu.out 30 | 31 | edit: 32 | @ 1>/dev/null 2>/dev/null gvim -p Makefile *.go 33 | 34 | editor: 35 | gofmt -l -s -w *.go 36 | go test -i 37 | go test 2>&1 | tee log 38 | go install -tags virtual.trace 39 | 40 | internalError: 41 | egrep -ho '"internal error.*"' *.go | sort | cat -n 42 | 43 | later: 44 | @grep -n $(grep) LATER * || true 45 | @grep -n $(grep) MAYBE * || true 46 | 47 | mem: clean 48 | go test -run @ -bench . -memprofile mem.out -memprofilerate 1 -timeout 24h 49 | go tool pprof -lines -web -alloc_space *.test mem.out 50 | 51 | nuke: clean 52 | go clean -i 53 | 54 | todo: 55 | @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true 56 | @grep -nr $(grep) TODO * | grep -v $(ngrep) || true 57 | @grep -nr $(grep) BUG * | grep -v $(ngrep) || true 58 | @grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true 59 | -------------------------------------------------------------------------------- /99trace/README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | 1. Usage 4 | 1. Installation 5 | 1. Changelog 6 | 1. Sample 7 | 8 | # 99trace 9 | 10 | Command 99trace traces execution of binary programs produced by the 99c compiler. 11 | 12 | The trace is written to stderr. 13 | 14 | ### Usage 15 | 16 | 99trace a.out [arguments] 17 | 18 | ### Installation 19 | 20 | To install or update 99trace 21 | 22 | $ go get [-u] -tags virtual.trace github.com/cznic/99c/99trace 23 | 24 | Online documentation: [godoc.org/github.com/cznic/99c/99trace](http://godoc.org/github.com/cznic/99c/99trace) 25 | 26 | ### Changelog 27 | 28 | 2017-10-09: Initial public release. 29 | 30 | ### Sample 31 | 32 | $ cd ../examples/hello/ 33 | $ 99c hello.c && 99trace a.out 2>log 34 | hello world 35 | $ cat log 36 | # _start 37 | 0x00002 func ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:13:1 38 | 0x00003 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 39 | 0x00004 push64 (ds) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 40 | 0x00005 push64 (ds+0x10); /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 41 | 0x00006 push64 (ds+0x20); /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 42 | 0x00007 #register_stdfiles ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 43 | 0x00008 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 44 | 0x00009 sub sp, 0x8 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 45 | 0x0000a arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 46 | 0x0000b push32 (ap-0x8) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 47 | 0x0000c push64 (ap-0x10); /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 48 | 0x0000d call 0x16 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 49 | # main 50 | 0x00016 func ; hello.c:3:1 51 | 0x00017 push ap ; hello.c:3:1 52 | 0x00018 zero32 ; hello.c:3:1 53 | 0x00019 store32 ; hello.c:3:1 54 | 0x0001a arguments ; hello.c:3:1 55 | 0x0001b push ts+0x0 ; hello.c:4:1 56 | 0x0001c #printf ; hello.c:4:1 57 | 0x0001d return ; hello.c:4:1 58 | 59 | 0x0000e #exit ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 60 | 61 | $ 62 | -------------------------------------------------------------------------------- /99trace/all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "path" 11 | "runtime" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func caller(s string, va ...interface{}) { 17 | if s == "" { 18 | s = strings.Repeat("%v ", len(va)) 19 | } 20 | _, fn, fl, _ := runtime.Caller(2) 21 | fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 22 | fmt.Fprintf(os.Stderr, s, va...) 23 | fmt.Fprintln(os.Stderr) 24 | _, fn, fl, _ = runtime.Caller(1) 25 | fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 26 | fmt.Fprintln(os.Stderr) 27 | os.Stderr.Sync() 28 | } 29 | 30 | func dbg(s string, va ...interface{}) { 31 | if s == "" { 32 | s = strings.Repeat("%v ", len(va)) 33 | } 34 | _, fn, fl, _ := runtime.Caller(1) 35 | fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 36 | fmt.Fprintf(os.Stderr, s, va...) 37 | fmt.Fprintln(os.Stderr) 38 | os.Stderr.Sync() 39 | } 40 | 41 | func TODO(...interface{}) string { //TODOOK 42 | _, fn, fl, _ := runtime.Caller(1) 43 | return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 44 | } 45 | 46 | func use(...interface{}) {} 47 | 48 | func init() { 49 | use(caller, dbg, TODO) //TODOOK 50 | } 51 | 52 | // ============================================================================ 53 | 54 | func Test(t *testing.T) { 55 | t.Logf("TODO") 56 | } 57 | -------------------------------------------------------------------------------- /99trace/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Command 99trace traces execution of binary programs produced by the 99c 6 | // compiler. 7 | // 8 | // The trace is output to stderr. 9 | // 10 | // Usage 11 | // 12 | // To trace a compiled program named a.out 13 | // 14 | // 99trace a.out [arguments] 15 | // 16 | // Installation 17 | // 18 | // To install or update 99trace 19 | // 20 | // $ go get [-u] -tags virtual.trace github.com/cznic/99c/99trace 21 | // 22 | // Online documentation: [godoc.org/github.com/cznic/99c/99trace](http://godoc.org/github.com/cznic/99c/99trace) 23 | // 24 | // Changelog 25 | // 26 | // 2017-10-09: Initial public release. 27 | // 28 | // Sample 29 | // 30 | // Example session 31 | // 32 | // $ cd ../examples/hello/ 33 | // $ 99c hello.c && 99trace a.out 2>log 34 | // hello world 35 | // $ cat log 36 | // # _start 37 | // 0x00002 func ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:13:1 38 | // 0x00003 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 39 | // 0x00004 push64 (ds) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 40 | // 0x00005 push64 (ds+0x10); /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 41 | // 0x00006 push64 (ds+0x20); /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 42 | // 0x00007 #register_stdfiles ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:14:1 43 | // 0x00008 arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 44 | // 0x00009 sub sp, 0x8 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 45 | // 0x0000a arguments ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 46 | // 0x0000b push32 (ap-0x8) ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 47 | // 0x0000c push64 (ap-0x10); /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 48 | // 0x0000d call 0x16 ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 49 | // # main 50 | // 0x00016 func ; hello.c:3:1 51 | // 0x00017 push ap ; hello.c:3:1 52 | // 0x00018 zero32 ; hello.c:3:1 53 | // 0x00019 store32 ; hello.c:3:1 54 | // 0x0001a arguments ; hello.c:3:1 55 | // 0x0001b push ts+0x0 ; hello.c:4:1 56 | // 0x0001c #printf ; hello.c:4:1 57 | // 0x0001d return ; hello.c:4:1 58 | // 59 | // 0x0000e #exit ; /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 60 | // 61 | // $ 62 | package main 63 | 64 | import ( 65 | "bufio" 66 | "fmt" 67 | "os" 68 | 69 | "github.com/cznic/virtual" 70 | ) 71 | 72 | func exit(code int, msg string, arg ...interface{}) { 73 | if msg != "" { 74 | fmt.Fprintf(os.Stderr, os.Args[0]+": "+msg, arg...) 75 | } 76 | os.Exit(code) 77 | } 78 | 79 | func main() { 80 | if !trace { 81 | exit(1, `This tool must be built using '-tags virtual.trace', please rebuild it. 82 | Use 83 | $ go install -tags virtual.trace github.com/cznic/99c/99trace 84 | or 85 | $ go get [-u] -tags virtual.trace github.com/cznic/99c/99trace 86 | `) 87 | } 88 | 89 | if len(os.Args) < 2 { 90 | exit(2, "invalid arguments %v\n", os.Args) 91 | } 92 | 93 | bin, err := os.Open(os.Args[1]) 94 | if err != nil { 95 | exit(1, "%v\n", err) 96 | } 97 | 98 | var b virtual.Binary 99 | if _, err := b.ReadFrom(bufio.NewReader(bin)); err != nil { 100 | exit(1, "%v\n", err) 101 | } 102 | 103 | code, err := virtual.Exec(&b, os.Args[1:], os.Stdin, os.Stdout, os.Stderr, 0, 8<<20, "") 104 | if err != nil { 105 | if code == 0 { 106 | code = 1 107 | } 108 | exit(code, "%v\n", err) 109 | } 110 | 111 | exit(code, "") 112 | } 113 | -------------------------------------------------------------------------------- /99trace/trace_disabled.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !virtual.trace 6 | 7 | package main 8 | 9 | const trace = false 10 | -------------------------------------------------------------------------------- /99trace/trace_enabled.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build virtual.trace 6 | 7 | package main 8 | 9 | const trace = true 10 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This file lists authors for copyright purposes. This file is distinct from 2 | # the CONTRIBUTORS files. See the latter for an explanation. 3 | # 4 | # Names should be added to this file as: 5 | # Name or Organization 6 | # 7 | # The email address is not required for organizations. 8 | # 9 | # Please keep the list sorted. 10 | 11 | Jan Mercl <0xjnml@gmail.com> 12 | Yasuhiro Matsumoto 13 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This file lists people who contributed code to this repository. The AUTHORS 2 | # file lists the copyright holders; this file lists people. 3 | # 4 | # Names should be added to this file like so: 5 | # Name 6 | # 7 | # Please keep the list sorted. 8 | 9 | Jan Mercl <0xjnml@gmail.com> 10 | Yasuhiro Matsumoto 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 The 99c Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the names of the authors nor the names of the 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The 99c Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | .PHONY: all clean cover cpu editor internalError later mem nuke todo edit 6 | 7 | grep=--include=*.go --include=*.c --include=*.h --include=*.yy --exclude-dir=lib/ 8 | ngrep='TODOOK\|parser\.go\|scanner\.go\|.*_string\.go' 9 | 10 | all: editor 11 | go vet 2>&1 | grep -v $(ngrep) || true 12 | golint 2>&1 | grep -v $(ngrep) || true 13 | make todo 14 | unused . || true 15 | misspell *.go 16 | gosimple || true 17 | maligned || true 18 | unconvert -apply 19 | 20 | clean: 21 | go clean 22 | rm -f *~ *.test *.out 23 | 24 | cover: 25 | t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t 26 | 27 | cpu: clean 28 | go test -run @ -bench . -cpuprofile cpu.out 29 | go tool pprof -lines *.test cpu.out 30 | 31 | edit: 32 | @ 1>/dev/null 2>/dev/null gvim -p Makefile *.go 33 | 34 | editor: 35 | find -name \*.c -or -name \*.h | xargs -n1 indent -linux -l -1 36 | find -name \*.c~ -or -name \*.h~ | xargs rm 37 | gofmt -l -s -w . 38 | go test -i 39 | go test 40 | go install -tags virtual.profile ./99prof 41 | go install -tags virtual.strace ./99strace 42 | go install -tags virtual.trace ./99trace 43 | go install ./ ./99dump ./99nm ./99run 44 | 45 | internalError: 46 | egrep -ho '"internal error.*"' *.go | sort | cat -n 47 | 48 | later: 49 | @grep -n $(grep) LATER * || true 50 | @grep -n $(grep) MAYBE * || true 51 | 52 | mem: clean 53 | go test -run @ -bench . -memprofile mem.out -memprofilerate 1 -timeout 24h 54 | go tool pprof -lines -web -alloc_space *.test mem.out 55 | 56 | nuke: clean 57 | go clean -i 58 | 59 | todo: 60 | @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true 61 | @grep -nr $(grep) TODO * | grep -v $(ngrep) || true 62 | @grep -nr $(grep) BUG * | grep -v $(ngrep) || true 63 | @grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `github.com/cznic/99c` has moved to [`modernc.org/99c`](https://godoc.org/modernc.org/99c) ([vcs](https://gitlab.com/cznic/99c)). 2 | 3 | Please update your import paths to `modernc.org/99c`. 4 | 5 | This repo is now archived. 6 | -------------------------------------------------------------------------------- /all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "io/ioutil" 10 | "os" 11 | "path" 12 | "path/filepath" 13 | "runtime" 14 | "strings" 15 | "testing" 16 | 17 | "github.com/cznic/ir" 18 | "github.com/cznic/virtual" 19 | "github.com/cznic/xc" 20 | ) 21 | 22 | func caller(s string, va ...interface{}) { 23 | if s == "" { 24 | s = strings.Repeat("%v ", len(va)) 25 | } 26 | _, fn, fl, _ := runtime.Caller(2) 27 | fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 28 | fmt.Fprintf(os.Stderr, s, va...) 29 | fmt.Fprintln(os.Stderr) 30 | _, fn, fl, _ = runtime.Caller(1) 31 | fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 32 | fmt.Fprintln(os.Stderr) 33 | os.Stderr.Sync() 34 | } 35 | 36 | func dbg(s string, va ...interface{}) { 37 | if s == "" { 38 | s = strings.Repeat("%v ", len(va)) 39 | } 40 | _, fn, fl, _ := runtime.Caller(1) 41 | fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 42 | fmt.Fprintf(os.Stderr, s, va...) 43 | fmt.Fprintln(os.Stderr) 44 | os.Stderr.Sync() 45 | } 46 | 47 | func TODO(...interface{}) string { //TODOOK 48 | _, fn, fl, _ := runtime.Caller(1) 49 | return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 50 | } 51 | 52 | func use(...interface{}) {} 53 | 54 | func init() { 55 | use(caller, dbg, TODO) //TODOOK 56 | } 57 | 58 | // ============================================================================ 59 | 60 | // https://github.com/cznic/99c/issues/4 61 | func TestIssue4(t *testing.T) { 62 | src, err := filepath.Abs("testdata/issue4.c") 63 | if err != nil { 64 | t.Fatal(err) 65 | } 66 | 67 | wd, err := os.Getwd() 68 | if err != nil { 69 | t.Fatal(err) 70 | } 71 | 72 | defer func() { 73 | if err := os.Chdir(wd); err != nil { 74 | t.Fatal(err) 75 | } 76 | }() 77 | 78 | dir, err := ioutil.TempDir("", "99c-test-") 79 | if err != nil { 80 | t.Fatal(err) 81 | } 82 | 83 | if err := os.Chdir(dir); err != nil { 84 | t.Fatal(err) 85 | } 86 | 87 | defer os.RemoveAll(dir) 88 | 89 | var obj, obj2 ir.Objects 90 | j := newTask() 91 | j.args.c = true 92 | j.args.hooks.obj = &obj 93 | j.args.args = []string{src} 94 | if err := j.main(); err != nil { 95 | t.Fatal(err) 96 | } 97 | 98 | objf := filepath.Join(dir, "issue4.o") 99 | f, err := os.Open(objf) 100 | if err != nil { 101 | t.Fatal(err) 102 | } 103 | 104 | if _, err := obj2.ReadFrom(f); err != nil { 105 | t.Fatal(err) 106 | } 107 | 108 | if err := f.Close(); err != nil { 109 | t.Fatal(err) 110 | } 111 | 112 | if g, e := ir.PrettyString(obj2), ir.PrettyString(obj); g != e { 113 | t.Fatalf("got\n%s\nexp\n%s", g, e) 114 | } 115 | 116 | var bin *virtual.Binary 117 | j = newTask() 118 | j.args.args = []string{objf} 119 | j.args.g = true 120 | j.args.hooks.bin = &bin 121 | if err := j.main(); err != nil { 122 | t.Fatal(err) 123 | } 124 | 125 | if _, ok := bin.Sym[ir.NameID(xc.Dict.SID("fib"))]; !ok { 126 | t.Fatalf("fib symbol missing: %v", bin.Sym) 127 | } 128 | } 129 | 130 | func TestLibToolConfig(t *testing.T) { 131 | m, err := filepath.Glob(filepath.Join("testdata", "*.la")) 132 | if err != nil { 133 | t.Fatal(err) 134 | } 135 | 136 | for _, v := range m { 137 | c, err := newLibToolConfigFile(v) 138 | if err != nil { 139 | t.Fatal(err) 140 | } 141 | 142 | t.Logf("%s: %#v", v, c) 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /ar.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bufio" 9 | "io" 10 | "os" 11 | 12 | "github.com/blakesmith/ar" 13 | "github.com/cznic/ir" 14 | ) 15 | 16 | func archive(fn string) (ir.Objects, error) { 17 | f, err := os.Open(fn) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | defer f.Close() 23 | 24 | var a ir.Objects 25 | r := ar.NewReader(bufio.NewReader(f)) 26 | for { 27 | if _, err := r.Next(); err != nil { 28 | if err == io.EOF { 29 | return a, nil 30 | } 31 | 32 | return nil, err 33 | } 34 | 35 | var o ir.Objects 36 | if _, err := o.ReadFrom(r); err != nil { 37 | return nil, err 38 | } 39 | 40 | if len(o) != 1 { 41 | panic("TODO") 42 | } 43 | 44 | a = append(a, o[0]) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Command 99c is a c99 compiler targeting a virtual machine. 6 | // 7 | // Usage 8 | // 9 | // Output of 99c -h 10 | // 11 | // 99c: Flags: 12 | // -99lib 13 | // Library link mode. 14 | // -Dname 15 | // Equivalent to inserting '#define name 1' at the start of the 16 | // translation unit. 17 | // -Dname=definition 18 | // Equivalent to inserting '#define name definition' at the start of the 19 | // translation unit. 20 | // -E Copy C-language source files to standard output, executing all 21 | // preprocessor directives; no compilation shall be performed. If any 22 | // operand is not a text file, the effects are unspecified. 23 | // -Ipath 24 | // Add path to the include files search paths. 25 | // -Lpath 26 | // Add path to search paths for -l. 27 | // -Olevel 28 | // Optimization setting, ignored. 29 | // -Wwarn 30 | // Warning level, ignored. 31 | // -ansi 32 | // Ignored. 33 | // -c Suppress the link-edit phase of the compilation, and do not 34 | // remove any object files that are produced. 35 | // -g Produce debugging information. 36 | // -l 37 | // Link with lib. 38 | // -o pathname 39 | // Use the specified pathname, instead of the default a.out, for 40 | // the executable file produced. If the -o option is present with 41 | // -c or -E, the result is unspecified. 42 | // -pedantic 43 | // Ignored. 44 | // -pthread 45 | // Ignored. (TODO) 46 | // -rdynamic 47 | // Ignored. (TODO) 48 | // -rpath pathname 49 | // Ignored. (TODO) 50 | // -shared 51 | // Link mode shared library. 52 | // -soname arg 53 | // Ignored. (TODO) 54 | // -99extra flag 55 | // Extra cc flags: 56 | // AlignOf 57 | // AlternateKeywords 58 | // AnonymousStructFields 59 | // Asm 60 | // BuiltinClassifyType 61 | // BuiltinConstantP 62 | // ComputedGotos 63 | // DlrInIdentifiers 64 | // EmptyDeclarations 65 | // EmptyDefine 66 | // EmptyStructs 67 | // ImaginarySuffix 68 | // ImplicitFuncDef 69 | // ImplicitIntType 70 | // IncludeNext 71 | // LegacyDesignators 72 | // NonConstStaticInitExpressions 73 | // Noreturn 74 | // OmitConditionalOperand 75 | // OmitFuncArgTypes 76 | // OmitFuncRetType 77 | // ParenthesizedCompoundStatemen 78 | // StaticAssert 79 | // TypeOf 80 | // UndefExtraTokens 81 | // UnsignedEnums 82 | // WideBitFieldTypes 83 | // WideEnumValues 84 | // 85 | // Rest of the input is a list of file names, either C (.c) files or object 86 | // (.o, .a) files. 87 | // 88 | // Installation 89 | // 90 | // To install or update the compiler and the virtual machine 91 | // 92 | // $ go get [-u] github.com/cznic/99c github.com/cznic/99c/99run 93 | // 94 | // To update the toolchain and rebuild all commands 95 | // 96 | // $ go generate 97 | // 98 | // Use the -x flag to view the commands executed. 99 | // 100 | // Online documentation: http://godoc.org/github.com/cznic/99c 101 | // 102 | // Changelog 103 | // 104 | // 2017-10-19: Handle ar files (.a). 105 | // 106 | // 2017-10-18: Executables should be from now on no more tied to a single 107 | // compatibility number but to a minimal compatibility number. No more 108 | // permanent recompiling of everything. 109 | // 110 | // 2017-10-18: Initial support for using C packages. 111 | // 112 | // 2017-10-18: The -g flag is no more ignored. Add the -g flag to have the 113 | // symbol and line information included in the executable. Without using -g 114 | // some tools may not work and stack traces will not be really useful. The 115 | // advantage of not including the additional info by default are substantially 116 | // smaller executables. 117 | // 118 | // 2017-10-07: Initial public release. 119 | // 120 | // Supported platforms and operating systems 121 | // 122 | // See: https://godoc.org/github.com/cznic/ccir#hdr-Supported_platforms_and_architectures 123 | // 124 | // At the time of this writing, in GOOS_GOARCH form 125 | // 126 | // linux_386 127 | // linux_amd64 128 | // windows_386 129 | // windows_amd64 130 | // 131 | // Porting to other platforms/architectures is considered not difficult. 132 | // 133 | // Options 134 | // 135 | // 136 | // Project status 137 | // 138 | // Both the compiler and the C runtime library implementation are known to be 139 | // incomplete. Missing pieces are added as needed. Please fill an issue when 140 | // you run into problems and be patient. Only limited resources can be 141 | // allocated to this project and to the related parts of the tool chain. 142 | // 143 | // Also, contributions are welcome. 144 | // 145 | // Executing compiled programs 146 | // 147 | // Running a binary on Linux 148 | // 149 | // $ ./a.out 150 | // hello world 151 | // $ 152 | // 153 | // Running a binary on Windows 154 | // 155 | // C:\> 99run a.out 156 | // hello world 157 | // C:\> 158 | // 159 | // A simple program 160 | // 161 | // All in just a single C file. 162 | // 163 | // $ cd examples/hello/ 164 | // $ cat hello.c 165 | // #include 166 | // 167 | // int main() { 168 | // printf("hello world\n"); 169 | // } 170 | // $ 99c hello.c && ./a.out 171 | // hello world 172 | // $ 173 | // 174 | // Setting the output file name 175 | // 176 | // If the output is a single file, use -o to set its name. (POSIX option) 177 | // 178 | // $ cd examples/hello/ 179 | // $ cat hello.c 180 | // #include 181 | // 182 | // int main() { 183 | // printf("hello world\n"); 184 | // } 185 | // $ 99c -o hello hello.c && ./hello 186 | // hello world 187 | // $ 188 | // 189 | // Obtaining the preprocessor output 190 | // 191 | // Use -E to produce the cpp results. (POSIX option) 192 | // 193 | // $ cd examples/hello/ 194 | // /home/jnml/src/github.com/cznic/99c/examples/hello 195 | // $ 99c -E hello.c 196 | // # 24 "/home/jnml/src/github.com/cznic/ccir/libc/predefined.h" 197 | // typedef char * __builtin_va_list ; 198 | // # 41 "/home/jnml/src/github.com/cznic/ccir/libc/builtin.h" 199 | // typedef __builtin_va_list __gnuc_va_list ; 200 | // typedef void * __FILE_TYPE__ ; 201 | // typedef void * __jmp_buf [ 7 ] ; 202 | // __FILE_TYPE__ __builtin_fopen ( char * __filename , char * __modes ) ; 203 | // long unsigned int __builtin_strlen ( char * __s ) ; 204 | // long unsigned int __builtin_bswap64 ( long unsigned int x ) ; 205 | // char * __builtin_strchr ( char * __s , int __c ) ; 206 | // char * __builtin_strcpy ( char * __dest , char * __src ) ; 207 | // double __builtin_copysign ( double x , double y ) ; 208 | // int __builtin_abs ( int j ) ; 209 | // ... 210 | // extern void flockfile ( FILE * __stream ) ; 211 | // extern int ftrylockfile ( FILE * __stream ) ; 212 | // extern void funlockfile ( FILE * __stream ) ; 213 | // # 3 "hello.c" 214 | // int main ( ) { 215 | // printf ( "hello world\n" ) ; 216 | // } 217 | // $ 218 | // 219 | // Multiple C files projects 220 | // 221 | // A translation unit may consist of multiple source files. 222 | // 223 | // $ cd examples/multifile/ 224 | // /home/jnml/src/github.com/cznic/99c/examples/multifile 225 | // $ cat main.c 226 | // char *hello(); 227 | // 228 | // #include 229 | // int main() { 230 | // printf("%s\n", hello()); 231 | // } 232 | // $ cat hello.c 233 | // char *hello() { 234 | // return "hello world"; 235 | // } 236 | // $ 99c main.c hello.c && ./a.out 237 | // hello world 238 | // $ 239 | // 240 | // Using object files 241 | // 242 | // Use -c to output object files. (POSIX otion) 243 | // 244 | // $ cd examples/multifile/ 245 | // /home/jnml/src/github.com/cznic/99c/examples/multifile 246 | // $ 99c -c hello.c main.c 247 | // $ 99c hello.o main.o && ./a.out 248 | // hello world 249 | // $ 99c hello.o main.c && ./a.out 250 | // hello world 251 | // $ 99c hello.c main.o && ./a.out 252 | // hello world 253 | // $ 254 | // 255 | // Stack traces 256 | // 257 | // If the program source(s) are available at the same location(s) as when the 258 | // program was compiled, then any stack trace produced is annotated using the 259 | // source code lines. 260 | // 261 | // $ cd examples/stack/ 262 | // /home/jnml/src/github.com/cznic/99c/examples/stack 263 | // $ cat stack.c 264 | // void f(int n) { 265 | // if (n) { 266 | // f(n-1); 267 | // return; 268 | // } 269 | // 270 | // *(char *)n; 271 | // } 272 | // 273 | // int main() { 274 | // f(4); 275 | // } 276 | // $ 99c stack.c && ./a.out 277 | // panic: runtime error: invalid memory address or nil pointer dereference [recovered] 278 | // panic: runtime error: invalid memory address or nil pointer dereference 279 | // stack.c.f(0x0) 280 | // stack.c:7:1 0x0002c load8 0x0 ; - // *(char *)n; 281 | // stack.c.f(0x1) 282 | // stack.c:3:1 0x00028 call 0x21 ; - // f(n-1); 283 | // stack.c.f(0x2) 284 | // stack.c:3:1 0x00028 call 0x21 ; - // f(n-1); 285 | // stack.c.f(0x3) 286 | // stack.c:3:1 0x00028 call 0x21 ; - // f(n-1); 287 | // stack.c.f(0x7f3400000004) 288 | // stack.c:3:1 0x00028 call 0x21 ; - // f(n-1); 289 | // stack.c.main(0x7f3400000001, 0x7f34c9400030) 290 | // stack.c:11:1 0x0001d call 0x21 ; - // f(4); 291 | // /home/jnml/src/github.com/cznic/ccir/libc/crt0.c._start(0x1, 0x7f34c9400030) 292 | // /home/jnml/src/github.com/cznic/ccir/libc/crt0.c:15:1 0x0000d call 0x16 ; - // __builtin_exit(((int (*)())main) (argc, argv)); 293 | // 294 | // [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x511e46] 295 | // 296 | // goroutine 1 [running]: 297 | // github.com/cznic/virtual.(*cpu).run.func1(0xc42009e2a0) 298 | // /home/jnml/src/github.com/cznic/virtual/cpu.go:222 +0x26e 299 | // panic(0x555340, 0x66a270) 300 | // /home/jnml/go/src/runtime/panic.go:491 +0x283 301 | // github.com/cznic/virtual.readI8(...) 302 | // /home/jnml/src/github.com/cznic/virtual/cpu.go:74 303 | // github.com/cznic/virtual.(*cpu).run(0xc42009e2a0, 0x2, 0x0, 0x0, 0x0) 304 | // /home/jnml/src/github.com/cznic/virtual/cpu.go:993 +0x2116 305 | // github.com/cznic/virtual.New(0xc4201d2000, 0xc42000a090, 0x1, 0x1, 0x656540, 0xc42000c010, 0x656580, 0xc42000c018, 0x656580, 0xc42000c020, ...) 306 | // /home/jnml/src/github.com/cznic/virtual/virtual.go:73 +0x2be 307 | // github.com/cznic/virtual.Exec(0xc4201d2000, 0xc42000a090, 0x1, 0x1, 0x656540, 0xc42000c010, 0x656580, 0xc42000c018, 0x656580, 0xc42000c020, ...) 308 | // /home/jnml/src/github.com/cznic/virtual/virtual.go:84 +0xe9 309 | // main.main() 310 | // /home/jnml/src/github.com/cznic/99c/99run/main.go:37 +0x382 311 | // $ 312 | // 313 | // Argument passing 314 | // 315 | // Command line arguments are passed the standard way. 316 | // 317 | // $ cd examples/args/ 318 | // /home/jnml/src/github.com/cznic/99c/examples/args 319 | // $ cat args.c 320 | // #include 321 | // 322 | // int main(int argc, char **argv) { 323 | // for (int i = 0; i < argc; i++) { 324 | // printf("%i: %s\n", i, argv[i]); 325 | // } 326 | // } 327 | // $ 99c args.c && ./a.out foo bar -x -y - qux 328 | // 0: ./a.out 329 | // 1: foo 330 | // 2: bar 331 | // 3: -x 332 | // 4: -y 333 | // 5: - 334 | // 6: qux 335 | // $ 336 | // 337 | // Executing a C program embedded in a Go program 338 | // 339 | // This example requires installation of additional tools 340 | // 341 | // $ go get -u github.com/cznic/assets github.com/cznic/httpfs 342 | // $ cd examples/embedding/ 343 | // /home/jnml/src/github.com/cznic/99c/examples/embedding 344 | // $ ls * 345 | // main.c main.go 346 | // 347 | // assets: 348 | // keepdir 349 | // $ cat main.c 350 | // // +build ignore 351 | // 352 | // #include 353 | // 354 | // int main() { 355 | // int c; 356 | // while ((c = getc(stdin)) != EOF) { 357 | // printf("%c", c >= 'a' && c <= 'z' ? c^' ' : c); 358 | // } 359 | // } 360 | // $ cat main.go 361 | // //go:generate 99c -o assets/a.out main.c 362 | // //go:generate assets 363 | // 364 | // package main 365 | // 366 | // import ( 367 | // "bytes" 368 | // "fmt" 369 | // "strings" 370 | // "time" 371 | // 372 | // "github.com/cznic/httpfs" 373 | // "github.com/cznic/virtual" 374 | // ) 375 | // 376 | // func main() { 377 | // fs := httpfs.NewFileSystem(assets, time.Now()) 378 | // f, err := fs.Open("/a.out") 379 | // if err != nil { 380 | // panic(err) 381 | // } 382 | // 383 | // var bin virtual.Binary 384 | // if _, err := bin.ReadFrom(f); err != nil { 385 | // panic(err) 386 | // } 387 | // 388 | // var out bytes.Buffer 389 | // exitCode, err := virtual.Exec(&bin, nil, strings.NewReader("Foo Bar"), &out, &out, 0, 1<<20, "") 390 | // if err != nil { 391 | // panic(err) 392 | // } 393 | // 394 | // fmt.Printf("%s\n%v\n", out.Bytes(), exitCode) 395 | // } 396 | // $ go generate && go build && ./embedding 397 | // FOO BAR 398 | // 0 399 | // $ 400 | // 401 | // Calling into an embedded C library from Go 402 | // 403 | // It's possible to call individual C functions from Go. 404 | // 405 | // This example requires installation of additional tools 406 | // 407 | // $ go get -u github.com/cznic/assets github.com/cznic/httpfs 408 | // $ cd examples/ffi/ 409 | // /home/jnml/src/github.com/cznic/99c/examples/ffi 410 | // $ ls * 411 | // lib42.c main.go 412 | // 413 | // assets: 414 | // keepdir 415 | // $ cat lib42.c 416 | // // +build ignore 417 | // 418 | // static int answer; 419 | // 420 | // int main() { 421 | // // Any library initialization comes here. 422 | // answer = 42; 423 | // } 424 | // 425 | // // Use the -99lib option to prevent the linker from eliminating this function. 426 | // int f42(int arg) { 427 | // return arg*answer; 428 | // } 429 | // $ cat main.go 430 | // //go:generate 99c -99lib -o assets/a.out lib42.c 431 | // //go:generate assets 432 | // 433 | // package main 434 | // 435 | // import ( 436 | // "fmt" 437 | // "time" 438 | // 439 | // "github.com/cznic/httpfs" 440 | // "github.com/cznic/ir" 441 | // "github.com/cznic/virtual" 442 | // "github.com/cznic/xc" 443 | // ) 444 | // 445 | // func main() { 446 | // fs := httpfs.NewFileSystem(assets, time.Now()) 447 | // f, err := fs.Open("/a.out") 448 | // if err != nil { 449 | // panic(err) 450 | // } 451 | // 452 | // var bin virtual.Binary 453 | // if _, err := bin.ReadFrom(f); err != nil { 454 | // panic(err) 455 | // } 456 | // 457 | // m, _, err := virtual.New(&bin, nil, nil, nil, nil, 0, 1<<10, "") 458 | // if err != nil { 459 | // panic(err) 460 | // } 461 | // 462 | // defer m.Close() 463 | // 464 | // pc, ok := bin.Sym[ir.NameID(xc.Dict.SID("f42"))] 465 | // if !ok { 466 | // panic("symbol not found") 467 | // } 468 | // 469 | // t, err := m.NewThread(1 << 10) 470 | // if err != nil { 471 | // panic(err) 472 | // } 473 | // 474 | // for _, v := range []int{-1, 0, 1} { 475 | // var y int32 476 | // _, err := t.FFI1(pc, virtual.Int32Result{&y}, virtual.Int32(int32(v))) 477 | // if err != nil { 478 | // panic(err) 479 | // } 480 | // 481 | // fmt.Println(y) 482 | // } 483 | // } 484 | // $ go generate && go build && ./ffi 485 | // -42 486 | // 0 487 | // 42 488 | // $ 489 | // 490 | // Loading C plugins at run-time 491 | // 492 | // It's possible to load C plugins at run-time. 493 | // 494 | // $ cd examples/plugin/ 495 | // /home/jnml/src/github.com/cznic/99c/examples/plugin 496 | // $ ls * 497 | // lib42.c main.go 498 | // $ cat lib42.c 499 | // // +build ignore 500 | // 501 | // static int answer; 502 | // 503 | // int main() { 504 | // // Any library initialization comes here. 505 | // answer = 42; 506 | // } 507 | // 508 | // // Use the -99lib option to prevent the linker from eliminating this function. 509 | // int f42(int arg) { 510 | // return arg*answer; 511 | // } 512 | // $ cat main.go 513 | // //go:generate 99c -99lib lib42.c 514 | // 515 | // package main 516 | // 517 | // import ( 518 | // "fmt" 519 | // "os" 520 | // 521 | // "github.com/cznic/ir" 522 | // "github.com/cznic/virtual" 523 | // "github.com/cznic/xc" 524 | // ) 525 | // 526 | // func main() { 527 | // f, err := os.Open("a.out") 528 | // if err != nil { 529 | // panic(err) 530 | // } 531 | // 532 | // var bin virtual.Binary 533 | // if _, err := bin.ReadFrom(f); err != nil { 534 | // panic(err) 535 | // } 536 | // 537 | // m, _, err := virtual.New(&bin, nil, nil, nil, nil, 0, 1<<10, "") 538 | // if err != nil { 539 | // panic(err) 540 | // } 541 | // 542 | // defer m.Close() 543 | // 544 | // pc, ok := bin.Sym[ir.NameID(xc.Dict.SID("f42"))] 545 | // if !ok { 546 | // panic("symbol not found") 547 | // } 548 | // 549 | // t, err := m.NewThread(1 << 10) 550 | // if err != nil { 551 | // panic(err) 552 | // } 553 | // 554 | // for _, v := range []int{1, 2, 3} { 555 | // var y int32 556 | // _, err := t.FFI1(pc, virtual.Int32Result{&y}, virtual.Int32(int32(v))) 557 | // if err != nil { 558 | // panic(err) 559 | // } 560 | // 561 | // fmt.Println(y) 562 | // } 563 | // } 564 | // $ go generate && go run main.go 565 | // 42 566 | // 84 567 | // 126 568 | // $ 569 | // 570 | // Inserting defines 571 | // 572 | // Use the -D flag to define additional macros on the command line. 573 | // 574 | // $ cd examples/define/ 575 | // /home/jnml/src/github.com/cznic/99c/examples/define 576 | // $ ls * 577 | // main.c 578 | // $ cat main.c 579 | // #include 580 | // 581 | // int main() { 582 | // #ifdef VERBOSE 583 | // printf(GREETING); 584 | // #endif 585 | // } 586 | // $ 99c -DVERBOSE -DGREETING=\"hello\\n\" main.c && ./a.out 587 | // hello 588 | // $ 99c -DGREETING=\"hello\\n\" main.c && ./a.out 589 | // $ 590 | // 591 | // Specifying include paths 592 | // 593 | // The -I flag defines additional include files search path(s). 594 | // 595 | // $ cd examples/include/ 596 | // /home/jnml/src/github.com/cznic/99c/examples/include 597 | // $ ls * 598 | // main.c 599 | // 600 | // foo: 601 | // main.h 602 | // $ cat main.c 603 | // #include 604 | // #include "main.h" 605 | // 606 | // int main() { 607 | // printf(HELLO); 608 | // } 609 | // $ cat foo/main.h 610 | // #ifndef _MAIN_H_ 611 | // #define _MAIN_H_ 612 | // 613 | // #define HELLO "hello\n" 614 | // 615 | // #endif 616 | // $ 99c main.c && ./a.out 617 | // 99c: main.c:2:10: include file not found: main.h (and 2 more errors) 618 | // $ 99c -Ifoo main.c && ./a.out 619 | // hello 620 | // $ 621 | // 622 | // Installing C packages 623 | // 624 | // To use a C package with programs compiled by 99c it's necessary to install a 625 | // 99c version of the package. The lib directory contains some such installers. 626 | // For example 627 | // 628 | // $ cd lib/xcb 629 | // $ go generate 630 | // 631 | // or equivalently 632 | // 633 | // $ go generate github.com/cznic/99c/lib/xcb 634 | // 635 | // will install the 99c version of libxcb on your system in '$HOME/.99c'. 636 | // Currently supported only on Linux. 637 | // 638 | // Talking to X server 639 | // 640 | // A bare bones example, currently supported only on Linux. 641 | // 642 | // $ go generate ./lib/xcb ./lib/xau 643 | // ... lot of output 644 | // $ cd examples/xcb/ 645 | // /home/jnml/src/github.com/cznic/99c/examples/xcb 646 | // $ ls 647 | // screen.c 648 | // $ cat screen.c 649 | // // +build ignore 650 | // 651 | // // src: https://xcb.freedesktop.org/tutorial/ 652 | // 653 | // #include 654 | // #include 655 | // #include 656 | // 657 | // int main() 658 | // { 659 | // /* Open the connection to the X server. Use the DISPLAY environment variable */ 660 | // 661 | // int i, screenNum; 662 | // xcb_connection_t *connection = xcb_connect(NULL, &screenNum); 663 | // 664 | // /* Get the screen whose number is screenNum */ 665 | // 666 | // const xcb_setup_t *setup = xcb_get_setup(connection); 667 | // xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); 668 | // 669 | // // we want the screen at index screenNum of the iterator 670 | // for (i = 0; i < screenNum; ++i) { 671 | // xcb_screen_next(&iter); 672 | // } 673 | // 674 | // xcb_screen_t *screen = iter.data; 675 | // 676 | // /* report */ 677 | // 678 | // printf("\n"); 679 | // printf("Informations of screen %" PRIu32 ":\n", screen->root); 680 | // printf(" width.........: %" PRIu16 "\n", screen->width_in_pixels); 681 | // printf(" height........: %" PRIu16 "\n", screen->height_in_pixels); 682 | // printf(" white pixel...: %" PRIu32 "\n", screen->white_pixel); 683 | // printf(" black pixel...: %" PRIu32 "\n", screen->black_pixel); 684 | // printf("\n"); 685 | // 686 | // return 0; 687 | // } 688 | // $ 99c screen.c -lxcb && ./a.out 689 | // 690 | // Informations of screen 927: 691 | // width.........: 1920 692 | // height........: 1200 693 | // white pixel...: 16777215 694 | // black pixel...: 0 695 | // 696 | // $ 697 | // 698 | // Creating a X window 699 | // 700 | // This example will show a small 150x150 pixel window in the top left corner 701 | // of the screen. The window content is not handled by this example, but it can 702 | // be moved, resized and closed. 703 | // 704 | // $ go generate ./lib/xcb ./lib/xau 705 | // ... lot of output 706 | // $ cd examples/xcb/ 707 | // $ cat helloworld.c 708 | // // +build ignore 709 | // 710 | // // src: https://www.x.org/releases/current/doc/libxcb/tutorial/index.html#helloworld 711 | // 712 | // #include 713 | // #include /* pause() */ 714 | // 715 | // #include 716 | // 717 | // int main() 718 | // { 719 | // xcb_connection_t *c; 720 | // xcb_screen_t *screen; 721 | // xcb_window_t win; 722 | // 723 | // /* Open the connection to the X server */ 724 | // c = xcb_connect(NULL, NULL); 725 | // 726 | // /* Get the first screen */ 727 | // screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; 728 | // screen = iter.data; 729 | // 730 | // /* Ask for our window's Id */ 731 | // win = xcb_generate_id(c); 732 | // 733 | // /* Create the window */ 734 | // xcb_create_window(c, /* Connection */ 735 | // XCB_COPY_FROM_PARENT, /* depth (same as root) */ 736 | // win, /* window Id */ 737 | // screen->root, /* parent window */ 738 | // 0, 0, /* x, y */ 739 | // 150, 150, /* width, height */ 740 | // 10, /* border_width */ 741 | // XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ 742 | // screen->root_visual, /* visual */ 743 | // 0, NULL); /* masks, not used yet */ 744 | // 745 | // /* Map the window on the screen */ 746 | // xcb_map_window(c, win); 747 | // 748 | // /* Make sure commands are sent before we pause, so window is shown */ 749 | // xcb_flush(c); 750 | // 751 | // printf("Close the demo window and/or press ctrl-c while the terminal is focused to exit.\n"); 752 | // int i = pause(); /* hold client until Ctrl-C */ 753 | // printf("pause() returned %i\n", i); 754 | // 755 | // return 0; 756 | // } 757 | // $ 99c helloworld.c -lxcb && ./a.out 758 | // Close the demo window and/or press ctrl-c while the terminal is focused to exit. 759 | // ... close the demo window (optional) 760 | // ... focus the terminal and press ctrl-c 761 | // ^Cpause() returned -1 762 | // $ 763 | package main 764 | -------------------------------------------------------------------------------- /examples/args/args.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | for (int i = 0; i < argc; i++) { 6 | printf("%i: %s\n", i, argv[i]); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/define/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | #ifdef VERBOSE 6 | printf(GREETING); 7 | #endif 8 | } 9 | -------------------------------------------------------------------------------- /examples/embedding/assets/keepdir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cznic/99c/beb9c29bf07cbc5b45bfa212ff170ff1c4677e39/examples/embedding/assets/keepdir -------------------------------------------------------------------------------- /examples/embedding/main.c: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | #include 4 | 5 | int main() 6 | { 7 | int c; 8 | while ((c = getc(stdin)) != EOF) { 9 | printf("%c", c >= 'a' && c <= 'z' ? c ^ ' ' : c); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/embedding/main.go: -------------------------------------------------------------------------------- 1 | //go:generate 99c -o assets/a.out main.c 2 | //go:generate assets 3 | 4 | package main 5 | 6 | import ( 7 | "bytes" 8 | "fmt" 9 | "strings" 10 | "time" 11 | 12 | "github.com/cznic/httpfs" 13 | "github.com/cznic/virtual" 14 | ) 15 | 16 | func main() { 17 | fs := httpfs.NewFileSystem(assets, time.Now()) 18 | f, err := fs.Open("/a.out") 19 | if err != nil { 20 | panic(err) 21 | } 22 | 23 | var bin virtual.Binary 24 | if _, err := bin.ReadFrom(f); err != nil { 25 | panic(err) 26 | } 27 | 28 | var out bytes.Buffer 29 | exitCode, err := virtual.Exec(&bin, nil, strings.NewReader("Foo Bar"), &out, &out, 0, 1<<20, "") 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | fmt.Printf("%s\n%v\n", out.Bytes(), exitCode) 35 | } 36 | -------------------------------------------------------------------------------- /examples/ffi/assets/keepdir: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cznic/99c/beb9c29bf07cbc5b45bfa212ff170ff1c4677e39/examples/ffi/assets/keepdir -------------------------------------------------------------------------------- /examples/ffi/lib42.c: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | static int answer; 4 | 5 | int main() 6 | { 7 | // Any library initialization comes here. 8 | answer = 42; 9 | } 10 | 11 | // Use the -99lib option to prevent the linker from eliminating this function. 12 | int f42(int arg) 13 | { 14 | return arg * answer; 15 | } 16 | -------------------------------------------------------------------------------- /examples/ffi/main.go: -------------------------------------------------------------------------------- 1 | //go:generate 99c -99lib -o assets/a.out lib42.c 2 | //go:generate assets 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "time" 9 | 10 | "github.com/cznic/httpfs" 11 | "github.com/cznic/ir" 12 | "github.com/cznic/virtual" 13 | "github.com/cznic/xc" 14 | ) 15 | 16 | func main() { 17 | fs := httpfs.NewFileSystem(assets, time.Now()) 18 | f, err := fs.Open("/a.out") 19 | if err != nil { 20 | panic(err) 21 | } 22 | 23 | var bin virtual.Binary 24 | if _, err := bin.ReadFrom(f); err != nil { 25 | panic(err) 26 | } 27 | 28 | m, _, err := virtual.New(&bin, nil, nil, nil, nil, 0, 1<<10, "") 29 | if err != nil { 30 | panic(err) 31 | } 32 | 33 | defer m.Close() 34 | 35 | pc, ok := bin.Sym[ir.NameID(xc.Dict.SID("f42"))] 36 | if !ok { 37 | panic("symbol not found") 38 | } 39 | 40 | t, err := m.NewThread(1 << 10) 41 | if err != nil { 42 | panic(err) 43 | } 44 | 45 | for _, v := range []int{-1, 0, 1} { 46 | var y int32 47 | _, err := t.FFI1(pc, virtual.Int32Result{&y}, virtual.Int32(int32(v))) 48 | if err != nil { 49 | panic(err) 50 | } 51 | 52 | fmt.Println(y) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /examples/hello/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("hello world\n"); 6 | } 7 | -------------------------------------------------------------------------------- /examples/include/foo/main.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAIN_H_ 2 | #define _MAIN_H_ 3 | 4 | #define HELLO "hello\n" 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /examples/include/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "main.h" 3 | 4 | int main() 5 | { 6 | printf(HELLO); 7 | } 8 | -------------------------------------------------------------------------------- /examples/multifile/hello.c: -------------------------------------------------------------------------------- 1 | char *hello() 2 | { 3 | return "hello world"; 4 | } 5 | -------------------------------------------------------------------------------- /examples/multifile/main.c: -------------------------------------------------------------------------------- 1 | char *hello(); 2 | 3 | #include 4 | int main() 5 | { 6 | printf("%s\n", hello()); 7 | } 8 | -------------------------------------------------------------------------------- /examples/nm/foo.c: -------------------------------------------------------------------------------- 1 | int i; 2 | 3 | static int j; 4 | 5 | int foo() 6 | { 7 | } 8 | 9 | static int bar() 10 | { 11 | } 12 | 13 | int main() 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /examples/plugin/lib42.c: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | static int answer; 4 | 5 | int main() 6 | { 7 | // Any library initialization comes here. 8 | answer = 42; 9 | } 10 | 11 | // Use the -99lib option to prevent the linker from eliminating this function. 12 | int f42(int arg) 13 | { 14 | return arg * answer; 15 | } 16 | -------------------------------------------------------------------------------- /examples/plugin/main.go: -------------------------------------------------------------------------------- 1 | //go:generate 99c -99lib lib42.c 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | 9 | "github.com/cznic/ir" 10 | "github.com/cznic/virtual" 11 | "github.com/cznic/xc" 12 | ) 13 | 14 | func main() { 15 | f, err := os.Open("a.out") 16 | if err != nil { 17 | panic(err) 18 | } 19 | 20 | var bin virtual.Binary 21 | if _, err := bin.ReadFrom(f); err != nil { 22 | panic(err) 23 | } 24 | 25 | m, _, err := virtual.New(&bin, nil, nil, nil, nil, 0, 1<<10, "") 26 | if err != nil { 27 | panic(err) 28 | } 29 | 30 | defer m.Close() 31 | 32 | pc, ok := bin.Sym[ir.NameID(xc.Dict.SID("f42"))] 33 | if !ok { 34 | panic("symbol not found") 35 | } 36 | 37 | t, err := m.NewThread(1 << 10) 38 | if err != nil { 39 | panic(err) 40 | } 41 | 42 | for _, v := range []int{1, 2, 3} { 43 | var y int32 44 | _, err := t.FFI1(pc, virtual.Int32Result{&y}, virtual.Int32(int32(v))) 45 | if err != nil { 46 | panic(err) 47 | } 48 | 49 | fmt.Println(y) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/prof/bogomips.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // src: https://en.wikipedia.org/wiki/BogoMips#Computation_of_BogoMIPS 5 | static void delay_loop(long loops) 6 | { 7 | long d0 = loops; 8 | do { 9 | --d0; 10 | } 11 | while (d0 >= 0); 12 | } 13 | 14 | int main(int argc, char **argv) 15 | { 16 | if (argc != 2) { 17 | return 2; 18 | } 19 | 20 | int n = atoi(argv[1]); 21 | if (n <= 0) { 22 | return 1; 23 | } 24 | 25 | delay_loop(n); 26 | } 27 | -------------------------------------------------------------------------------- /examples/prof/fib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int fib(int n) 5 | { 6 | switch (n) { 7 | case 0: 8 | return 0; 9 | case 1: 10 | return 1; 11 | default: 12 | return fib(n - 1) + fib(n - 2); 13 | } 14 | } 15 | 16 | int main(int argc, char **argv) 17 | { 18 | if (argc != 2) { 19 | return 2; 20 | } 21 | 22 | int n = atoi(argv[1]); 23 | if (n <= 0 || n > 40) { 24 | return 1; 25 | } 26 | 27 | printf("%i\n", fib(n)); 28 | } 29 | -------------------------------------------------------------------------------- /examples/stack/stack.c: -------------------------------------------------------------------------------- 1 | void f(int n) 2 | { 3 | if (n) { 4 | f(n - 1); 5 | return; 6 | } 7 | 8 | *(char *)n; 9 | } 10 | 11 | int main() 12 | { 13 | f(4); 14 | } 15 | -------------------------------------------------------------------------------- /examples/strace/data.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum. 2 | -------------------------------------------------------------------------------- /examples/strace/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define BUFSIZE 1<<16 6 | 7 | int main(int argc, char **argv) 8 | { 9 | char *buf = malloc(BUFSIZE); 10 | if (!buf) { 11 | return 1; 12 | } 13 | 14 | for (int i = 1; i < argc; i++) { 15 | int fd = open(argv[i], O_RDWR); 16 | if (fd < 0) { 17 | return 1; 18 | } 19 | 20 | ssize_t n; 21 | while ((n = read(fd, buf, BUFSIZE)) > 0) { 22 | write(0, buf, n); 23 | } 24 | } 25 | free(buf); 26 | } 27 | -------------------------------------------------------------------------------- /examples/xcb/drawingprimitives.c: -------------------------------------------------------------------------------- 1 | // 99c drawingprimitives.c -lxcb && ./a.out 2 | 3 | // +build ignore 4 | 5 | // src: https://www.x.org/releases/current/doc/libxcb/tutorial/index.html#drawingprim 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | int main() 13 | { 14 | xcb_connection_t *c; 15 | xcb_screen_t *screen; 16 | xcb_drawable_t win; 17 | xcb_gcontext_t foreground; 18 | xcb_generic_event_t *e; 19 | uint32_t mask = 0; 20 | uint32_t values[2]; 21 | 22 | /* geometric objects */ 23 | xcb_point_t points[] = { 24 | {10, 10}, 25 | {10, 20}, 26 | {20, 10}, 27 | {20, 20} 28 | }; 29 | 30 | xcb_point_t polyline[] = { 31 | {50, 10}, 32 | {5, 20}, /* rest of points are relative */ 33 | {25, -20}, 34 | {10, 10} 35 | }; 36 | 37 | xcb_segment_t segments[] = { 38 | {100, 10, 140, 30}, 39 | {110, 25, 130, 60} 40 | }; 41 | 42 | xcb_rectangle_t rectangles[] = { 43 | {10, 50, 40, 20}, 44 | {80, 50, 10, 40} 45 | }; 46 | 47 | xcb_arc_t arcs[] = { 48 | {10, 100, 60, 40, 0, 90 << 6}, 49 | {90, 100, 55, 40, 0, 270 << 6} 50 | }; 51 | 52 | /* Open the connection to the X server */ 53 | c = xcb_connect(NULL, NULL); 54 | 55 | /* Get the first screen */ 56 | screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; 57 | 58 | /* Create black (foreground) graphic context */ 59 | win = screen->root; 60 | 61 | foreground = xcb_generate_id(c); 62 | mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; 63 | values[0] = screen->black_pixel; 64 | values[1] = 0; 65 | xcb_create_gc(c, foreground, win, mask, values); 66 | 67 | /* Ask for our window's Id */ 68 | win = xcb_generate_id(c); 69 | 70 | /* Create the window */ 71 | mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 72 | values[0] = screen->white_pixel; 73 | values[1] = XCB_EVENT_MASK_EXPOSURE; 74 | xcb_create_window(c, /* Connection */ 75 | XCB_COPY_FROM_PARENT, /* depth */ 76 | win, /* window Id */ 77 | screen->root, /* parent window */ 78 | 0, 0, /* x, y */ 79 | 150, 150, /* width, height */ 80 | 10, /* border_width */ 81 | XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ 82 | screen->root_visual, /* visual */ 83 | mask, values); /* masks */ 84 | 85 | /* Map the window on the screen */ 86 | xcb_map_window(c, win); 87 | 88 | /* We flush the request */ 89 | xcb_flush(c); 90 | 91 | while ((e = xcb_wait_for_event(c))) { 92 | switch (e->response_type & ~0x80) { 93 | case XCB_EXPOSE:{ 94 | /* We draw the points */ 95 | xcb_poly_point(c, XCB_COORD_MODE_ORIGIN, win, foreground, 4, points); 96 | 97 | /* We draw the polygonal line */ 98 | xcb_poly_line(c, XCB_COORD_MODE_PREVIOUS, win, foreground, 4, polyline); 99 | 100 | /* We draw the segements */ 101 | xcb_poly_segment(c, win, foreground, 2, segments); 102 | 103 | /* We draw the rectangles */ 104 | xcb_poly_rectangle(c, win, foreground, 2, rectangles); 105 | 106 | /* We draw the arcs */ 107 | xcb_poly_arc(c, win, foreground, 2, arcs); 108 | 109 | /* We flush the request */ 110 | xcb_flush(c); 111 | 112 | break; 113 | } 114 | default:{ 115 | /* Unknown event type, ignore it */ 116 | break; 117 | } 118 | } 119 | /* Free the Generic Event */ 120 | free(e); 121 | } 122 | 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /examples/xcb/eventex.c: -------------------------------------------------------------------------------- 1 | // 99c eventex.c -lxcb && ./a.out 2 | 3 | // +build ignore 4 | 5 | // src: https://www.x.org/releases/current/doc/libxcb/tutorial/index.html#eventex 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | void print_modifiers(uint32_t mask) 13 | { 14 | const char **mod, *mods[] = { 15 | "Shift", "Lock", "Ctrl", "Alt", 16 | "Mod2", "Mod3", "Mod4", "Mod5", 17 | "Button1", "Button2", "Button3", "Button4", "Button5" 18 | }; 19 | printf("Modifier mask: "); 20 | for (mod = mods; mask; mask >>= 1, mod++) 21 | if (mask & 1) 22 | printf(*mod); 23 | putchar('\n'); 24 | } 25 | 26 | int main() 27 | { 28 | xcb_connection_t *c; 29 | xcb_screen_t *screen; 30 | xcb_window_t win; 31 | xcb_generic_event_t *e; 32 | uint32_t mask = 0; 33 | uint32_t values[2]; 34 | 35 | /* Open the connection to the X server */ 36 | c = xcb_connect(NULL, NULL); 37 | 38 | /* Get the first screen */ 39 | screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; 40 | 41 | /* Ask for our window's Id */ 42 | win = xcb_generate_id(c); 43 | 44 | /* Create the window */ 45 | mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 46 | values[0] = screen->white_pixel; 47 | values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE; 48 | xcb_create_window(c, /* Connection */ 49 | 0, /* depth */ 50 | win, /* window Id */ 51 | screen->root, /* parent window */ 52 | 0, 0, /* x, y */ 53 | 150, 150, /* width, height */ 54 | 10, /* border_width */ 55 | XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ 56 | screen->root_visual, /* visual */ 57 | mask, values); /* masks */ 58 | 59 | /* Map the window on the screen */ 60 | xcb_map_window(c, win); 61 | 62 | xcb_flush(c); 63 | 64 | while ((e = xcb_wait_for_event(c))) { 65 | switch (e->response_type & ~0x80) { 66 | case XCB_EXPOSE:{ 67 | xcb_expose_event_t *ev = (xcb_expose_event_t *) e; 68 | 69 | printf("Window %ld exposed. Region to be redrawn at location (%d,%d), with dimension (%d,%d)\n", ev->window, ev->x, ev->y, ev->width, ev->height); 70 | break; 71 | } 72 | case XCB_BUTTON_PRESS:{ 73 | xcb_button_press_event_t *ev = (xcb_button_press_event_t *) e; 74 | print_modifiers(ev->state); 75 | 76 | switch (ev->detail) { 77 | case 4: 78 | printf("Wheel Button up in window %ld, at coordinates (%d,%d)\n", ev->event, ev->event_x, ev->event_y); 79 | break; 80 | case 5: 81 | printf("Wheel Button down in window %ld, at coordinates (%d,%d)\n", ev->event, ev->event_x, ev->event_y); 82 | break; 83 | default: 84 | printf("Button %d pressed in window %ld, at coordinates (%d,%d)\n", ev->detail, ev->event, ev->event_x, ev->event_y); 85 | } 86 | break; 87 | } 88 | case XCB_BUTTON_RELEASE:{ 89 | xcb_button_release_event_t *ev = (xcb_button_release_event_t *) e; 90 | print_modifiers(ev->state); 91 | 92 | printf("Button %d released in window %ld, at coordinates (%d,%d)\n", ev->detail, ev->event, ev->event_x, ev->event_y); 93 | break; 94 | } 95 | case XCB_MOTION_NOTIFY:{ 96 | xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *) e; 97 | 98 | printf("Mouse moved in window %ld, at coordinates (%d,%d)\n", ev->event, ev->event_x, ev->event_y); 99 | break; 100 | } 101 | case XCB_ENTER_NOTIFY:{ 102 | xcb_enter_notify_event_t *ev = (xcb_enter_notify_event_t *) e; 103 | 104 | printf("Mouse entered window %ld, at coordinates (%d,%d)\n", ev->event, ev->event_x, ev->event_y); 105 | break; 106 | } 107 | case XCB_LEAVE_NOTIFY:{ 108 | xcb_leave_notify_event_t *ev = (xcb_leave_notify_event_t *) e; 109 | 110 | printf("Mouse left window %ld, at coordinates (%d,%d)\n", ev->event, ev->event_x, ev->event_y); 111 | break; 112 | } 113 | case XCB_KEY_PRESS:{ 114 | xcb_key_press_event_t *ev = (xcb_key_press_event_t *) e; 115 | print_modifiers(ev->state); 116 | 117 | printf("Key pressed in window %ld\n", ev->event); 118 | break; 119 | } 120 | case XCB_KEY_RELEASE:{ 121 | xcb_key_release_event_t *ev = (xcb_key_release_event_t *) e; 122 | print_modifiers(ev->state); 123 | 124 | printf("Key released in window %ld\n", ev->event); 125 | break; 126 | } 127 | default: 128 | /* Unknown event type, ignore it */ 129 | printf("Unknown event: %d\n", e->response_type); 130 | break; 131 | } 132 | /* Free the Generic Event */ 133 | free(e); 134 | } 135 | 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /examples/xcb/fontcompleteexample.c: -------------------------------------------------------------------------------- 1 | // 99c fontcompleteexample.c -lxcb && ./a.out 2 | 3 | // +build ignore 4 | 5 | // src: https://www.x.org/releases/current/doc/libxcb/tutorial/index.html#fontcompleteexample 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #define WIDTH 300 14 | #define HEIGHT 100 15 | 16 | static xcb_gc_t gc_font_get(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, const char *font_name); 17 | 18 | static void text_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label); 19 | 20 | static void text_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label) 21 | { 22 | xcb_void_cookie_t cookie_gc; 23 | xcb_void_cookie_t cookie_text; 24 | xcb_generic_error_t *error; 25 | xcb_gcontext_t gc; 26 | uint8_t length; 27 | 28 | length = strlen(label); 29 | 30 | gc = gc_font_get(c, screen, window, "7x13"); 31 | 32 | cookie_text = xcb_image_text_8_checked(c, length, window, gc, x1, y1, label); 33 | error = xcb_request_check(c, cookie_text); 34 | if (error) { 35 | fprintf(stderr, "ERROR: can't paste text : %d\n", error->error_code); 36 | xcb_disconnect(c); 37 | exit(-1); 38 | } 39 | 40 | cookie_gc = xcb_free_gc(c, gc); 41 | error = xcb_request_check(c, cookie_gc); 42 | if (error) { 43 | fprintf(stderr, "ERROR: can't free gc : %d\n", error->error_code); 44 | xcb_disconnect(c); 45 | exit(-1); 46 | } 47 | } 48 | 49 | static xcb_gc_t gc_font_get(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, const char *font_name) 50 | { 51 | uint32_t value_list[3]; 52 | xcb_void_cookie_t cookie_font; 53 | xcb_void_cookie_t cookie_gc; 54 | xcb_generic_error_t *error; 55 | xcb_font_t font; 56 | xcb_gcontext_t gc; 57 | uint32_t mask; 58 | 59 | font = xcb_generate_id(c); 60 | cookie_font = xcb_open_font_checked(c, font, strlen(font_name), font_name); 61 | 62 | error = xcb_request_check(c, cookie_font); 63 | if (error) { 64 | fprintf(stderr, "ERROR: can't open font : %d\n", error->error_code); 65 | xcb_disconnect(c); 66 | return -1; 67 | } 68 | 69 | gc = xcb_generate_id(c); 70 | mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; 71 | value_list[0] = screen->black_pixel; 72 | value_list[1] = screen->white_pixel; 73 | value_list[2] = font; 74 | cookie_gc = xcb_create_gc_checked(c, gc, window, mask, value_list); 75 | error = xcb_request_check(c, cookie_gc); 76 | if (error) { 77 | fprintf(stderr, "ERROR: can't create gc : %d\n", error->error_code); 78 | xcb_disconnect(c); 79 | exit(-1); 80 | } 81 | 82 | cookie_font = xcb_close_font_checked(c, font); 83 | error = xcb_request_check(c, cookie_font); 84 | if (error) { 85 | fprintf(stderr, "ERROR: can't close font : %d\n", error->error_code); 86 | xcb_disconnect(c); 87 | exit(-1); 88 | } 89 | 90 | return gc; 91 | } 92 | 93 | int main() 94 | { 95 | xcb_screen_iterator_t screen_iter; 96 | xcb_connection_t *c; 97 | const xcb_setup_t *setup; 98 | xcb_screen_t *screen; 99 | xcb_generic_event_t *e; 100 | xcb_generic_error_t *error; 101 | xcb_void_cookie_t cookie_window; 102 | xcb_void_cookie_t cookie_map; 103 | xcb_window_t window; 104 | uint32_t mask; 105 | uint32_t values[2]; 106 | int screen_number; 107 | 108 | /* getting the connection */ 109 | c = xcb_connect(NULL, &screen_number); 110 | if (!c) { 111 | fprintf(stderr, "ERROR: can't connect to an X server\n"); 112 | return -1; 113 | } 114 | 115 | /* getting the current screen */ 116 | setup = xcb_get_setup(c); 117 | 118 | screen = NULL; 119 | screen_iter = xcb_setup_roots_iterator(setup); 120 | for (; screen_iter.rem != 0; --screen_number, xcb_screen_next(&screen_iter)) 121 | if (screen_number == 0) { 122 | screen = screen_iter.data; 123 | break; 124 | } 125 | if (!screen) { 126 | fprintf(stderr, "ERROR: can't get the current screen\n"); 127 | xcb_disconnect(c); 128 | return -1; 129 | } 130 | 131 | /* creating the window */ 132 | window = xcb_generate_id(c); 133 | mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 134 | values[0] = screen->white_pixel; 135 | values[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION; 136 | cookie_window = xcb_create_window_checked(c, screen->root_depth, window, screen->root, 20, 200, WIDTH, HEIGHT, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values); 137 | cookie_map = xcb_map_window_checked(c, window); 138 | 139 | /* error managing */ 140 | error = xcb_request_check(c, cookie_window); 141 | if (error) { 142 | fprintf(stderr, "ERROR: can't create window : %d\n", error->error_code); 143 | xcb_disconnect(c); 144 | return -1; 145 | } 146 | error = xcb_request_check(c, cookie_map); 147 | if (error) { 148 | fprintf(stderr, "ERROR: can't map window : %d\n", error->error_code); 149 | xcb_disconnect(c); 150 | return -1; 151 | } 152 | 153 | xcb_flush(c); 154 | 155 | while (1) { 156 | e = xcb_poll_for_event(c); 157 | if (e) { 158 | switch (e->response_type & ~0x80) { 159 | case XCB_EXPOSE:{ 160 | char *text; 161 | 162 | text = "Press ESC key to exit..."; 163 | text_draw(c, screen, window, 10, HEIGHT - 10, text); 164 | break; 165 | } 166 | case XCB_KEY_RELEASE:{ 167 | xcb_key_release_event_t *ev; 168 | 169 | ev = (xcb_key_release_event_t *) e; 170 | 171 | switch (ev->detail) { 172 | /* ESC */ 173 | case 9: 174 | free(e); 175 | xcb_disconnect(c); 176 | return 0; 177 | } 178 | } 179 | } 180 | free(e); 181 | } 182 | } 183 | 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /examples/xcb/helloworld.c: -------------------------------------------------------------------------------- 1 | // 99c helloworld.c -lxcb && ./a.out 2 | 3 | // +build ignore 4 | 5 | // src: https://www.x.org/releases/current/doc/libxcb/tutorial/index.html#helloworld 6 | 7 | #include 8 | #include /* pause() */ 9 | 10 | #include 11 | 12 | int main() 13 | { 14 | xcb_connection_t *c; 15 | xcb_screen_t *screen; 16 | xcb_window_t win; 17 | 18 | /* Open the connection to the X server */ 19 | c = xcb_connect(NULL, NULL); 20 | 21 | /* Get the first screen */ 22 | screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; 23 | 24 | /* Ask for our window's Id */ 25 | win = xcb_generate_id(c); 26 | 27 | /* Create the window */ 28 | xcb_create_window(c, /* Connection */ 29 | XCB_COPY_FROM_PARENT, /* depth (same as root) */ 30 | win, /* window Id */ 31 | screen->root, /* parent window */ 32 | 0, 0, /* x, y */ 33 | 150, 150, /* width, height */ 34 | 10, /* border_width */ 35 | XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ 36 | screen->root_visual, /* visual */ 37 | 0, NULL); /* masks, not used yet */ 38 | 39 | /* Map the window on the screen */ 40 | xcb_map_window(c, win); 41 | 42 | /* Make sure commands are sent before we pause, so window is shown */ 43 | xcb_flush(c); 44 | 45 | printf("Close the demo window and/or press ctrl-c while the terminal is focused to exit.\n"); 46 | int i = pause(); /* hold client until Ctrl-C */ 47 | printf("pause() returned %i\n", i); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /examples/xcb/mousecursorexample.c: -------------------------------------------------------------------------------- 1 | // 99c mousecursorexample.c -lxcb && ./a.out 2 | 3 | // +build ignore 4 | 5 | // src: https://www.x.org/releases/current/doc/libxcb/tutorial/index.html#mousecursorexample 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #define WIDTH 300 14 | #define HEIGHT 150 15 | 16 | static xcb_gc_t gc_font_get(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, const char *font_name); 17 | 18 | static void button_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label); 19 | 20 | static void text_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label); 21 | 22 | static void cursor_set(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int cursor_id); 23 | 24 | static void button_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label) 25 | { 26 | xcb_point_t points[5]; 27 | xcb_void_cookie_t cookie_gc; 28 | xcb_void_cookie_t cookie_line; 29 | xcb_void_cookie_t cookie_text; 30 | xcb_generic_error_t *error; 31 | xcb_gcontext_t gc; 32 | int16_t width; 33 | int16_t height; 34 | uint8_t length; 35 | int16_t inset; 36 | 37 | length = strlen(label); 38 | inset = 2; 39 | 40 | gc = gc_font_get(c, screen, window, "7x13"); 41 | 42 | width = 7 * length + 2 * (inset + 1); 43 | height = 13 + 2 * (inset + 1); 44 | points[0].x = x1; 45 | points[0].y = y1; 46 | points[1].x = x1 + width; 47 | points[1].y = y1; 48 | points[2].x = x1 + width; 49 | points[2].y = y1 - height; 50 | points[3].x = x1; 51 | points[3].y = y1 - height; 52 | points[4].x = x1; 53 | points[4].y = y1; 54 | cookie_line = xcb_poly_line_checked(c, XCB_COORD_MODE_ORIGIN, window, gc, 5, points); 55 | 56 | error = xcb_request_check(c, cookie_line); 57 | if (error) { 58 | fprintf(stderr, "ERROR: can't draw lines : %d\n", error->error_code); 59 | xcb_disconnect(c); 60 | exit(-1); 61 | } 62 | 63 | cookie_text = xcb_image_text_8_checked(c, length, window, gc, x1 + inset + 1, y1 - inset - 1, label); 64 | error = xcb_request_check(c, cookie_text); 65 | if (error) { 66 | fprintf(stderr, "ERROR: can't paste text : %d\n", error->error_code); 67 | xcb_disconnect(c); 68 | exit(-1); 69 | } 70 | 71 | cookie_gc = xcb_free_gc(c, gc); 72 | error = xcb_request_check(c, cookie_gc); 73 | if (error) { 74 | fprintf(stderr, "ERROR: can't free gc : %d\n", error->error_code); 75 | xcb_disconnect(c); 76 | exit(-1); 77 | } 78 | } 79 | 80 | static void text_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label) 81 | { 82 | xcb_void_cookie_t cookie_gc; 83 | xcb_void_cookie_t cookie_text; 84 | xcb_generic_error_t *error; 85 | xcb_gcontext_t gc; 86 | uint8_t length; 87 | 88 | length = strlen(label); 89 | 90 | gc = gc_font_get(c, screen, window, "7x13"); 91 | 92 | cookie_text = xcb_image_text_8_checked(c, length, window, gc, x1, y1, label); 93 | error = xcb_request_check(c, cookie_text); 94 | if (error) { 95 | fprintf(stderr, "ERROR: can't paste text : %d\n", error->error_code); 96 | xcb_disconnect(c); 97 | exit(-1); 98 | } 99 | 100 | cookie_gc = xcb_free_gc(c, gc); 101 | error = xcb_request_check(c, cookie_gc); 102 | if (error) { 103 | fprintf(stderr, "ERROR: can't free gc : %d\n", error->error_code); 104 | xcb_disconnect(c); 105 | exit(-1); 106 | } 107 | } 108 | 109 | static xcb_gc_t gc_font_get(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, const char *font_name) 110 | { 111 | uint32_t value_list[3]; 112 | xcb_void_cookie_t cookie_font; 113 | xcb_void_cookie_t cookie_gc; 114 | xcb_generic_error_t *error; 115 | xcb_font_t font; 116 | xcb_gcontext_t gc; 117 | uint32_t mask; 118 | 119 | font = xcb_generate_id(c); 120 | cookie_font = xcb_open_font_checked(c, font, strlen(font_name), font_name); 121 | 122 | error = xcb_request_check(c, cookie_font); 123 | if (error) { 124 | fprintf(stderr, "ERROR: can't open font : %d\n", error->error_code); 125 | xcb_disconnect(c); 126 | return -1; 127 | } 128 | 129 | gc = xcb_generate_id(c); 130 | mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; 131 | value_list[0] = screen->black_pixel; 132 | value_list[1] = screen->white_pixel; 133 | value_list[2] = font; 134 | cookie_gc = xcb_create_gc_checked(c, gc, window, mask, value_list); 135 | error = xcb_request_check(c, cookie_gc); 136 | if (error) { 137 | fprintf(stderr, "ERROR: can't create gc : %d\n", error->error_code); 138 | xcb_disconnect(c); 139 | exit(-1); 140 | } 141 | 142 | cookie_font = xcb_close_font_checked(c, font); 143 | error = xcb_request_check(c, cookie_font); 144 | if (error) { 145 | fprintf(stderr, "ERROR: can't close font : %d\n", error->error_code); 146 | xcb_disconnect(c); 147 | exit(-1); 148 | } 149 | 150 | return gc; 151 | } 152 | 153 | static void cursor_set(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int cursor_id) 154 | { 155 | uint32_t values_list[3]; 156 | xcb_void_cookie_t cookie_font; 157 | xcb_void_cookie_t cookie_gc; 158 | xcb_generic_error_t *error; 159 | xcb_font_t font; 160 | xcb_cursor_t cursor; 161 | xcb_gcontext_t gc; 162 | uint32_t mask; 163 | uint32_t value_list; 164 | 165 | font = xcb_generate_id(c); 166 | cookie_font = xcb_open_font_checked(c, font, strlen("cursor"), "cursor"); 167 | error = xcb_request_check(c, cookie_font); 168 | if (error) { 169 | fprintf(stderr, "ERROR: can't open font : %d\n", error->error_code); 170 | xcb_disconnect(c); 171 | exit(-1); 172 | } 173 | 174 | cursor = xcb_generate_id(c); 175 | xcb_create_glyph_cursor(c, cursor, font, font, cursor_id, cursor_id + 1, 0, 0, 0, 0, 0, 0); 176 | 177 | gc = xcb_generate_id(c); 178 | mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; 179 | values_list[0] = screen->black_pixel; 180 | values_list[1] = screen->white_pixel; 181 | values_list[2] = font; 182 | cookie_gc = xcb_create_gc_checked(c, gc, window, mask, values_list); 183 | error = xcb_request_check(c, cookie_gc); 184 | if (error) { 185 | fprintf(stderr, "ERROR: can't create gc : %d\n", error->error_code); 186 | xcb_disconnect(c); 187 | exit(-1); 188 | } 189 | 190 | mask = XCB_CW_CURSOR; 191 | value_list = cursor; 192 | xcb_change_window_attributes(c, window, mask, &value_list); 193 | 194 | xcb_free_cursor(c, cursor); 195 | 196 | cookie_font = xcb_close_font_checked(c, font); 197 | error = xcb_request_check(c, cookie_font); 198 | if (error) { 199 | fprintf(stderr, "ERROR: can't close font : %d\n", error->error_code); 200 | xcb_disconnect(c); 201 | exit(-1); 202 | } 203 | } 204 | 205 | int main() 206 | { 207 | xcb_screen_iterator_t screen_iter; 208 | xcb_connection_t *c; 209 | const xcb_setup_t *setup; 210 | xcb_screen_t *screen; 211 | xcb_generic_event_t *e; 212 | xcb_generic_error_t *error; 213 | xcb_void_cookie_t cookie_window; 214 | xcb_void_cookie_t cookie_map; 215 | xcb_window_t window; 216 | uint32_t mask; 217 | uint32_t values[2]; 218 | int screen_number; 219 | uint8_t is_hand = 0; 220 | 221 | /* getting the connection */ 222 | c = xcb_connect(NULL, &screen_number); 223 | if (!c) { 224 | fprintf(stderr, "ERROR: can't connect to an X server\n"); 225 | return -1; 226 | } 227 | 228 | /* getting the current screen */ 229 | setup = xcb_get_setup(c); 230 | 231 | screen = NULL; 232 | screen_iter = xcb_setup_roots_iterator(setup); 233 | for (; screen_iter.rem != 0; --screen_number, xcb_screen_next(&screen_iter)) 234 | if (screen_number == 0) { 235 | screen = screen_iter.data; 236 | break; 237 | } 238 | if (!screen) { 239 | fprintf(stderr, "ERROR: can't get the current screen\n"); 240 | xcb_disconnect(c); 241 | return -1; 242 | } 243 | 244 | /* creating the window */ 245 | window = xcb_generate_id(c); 246 | mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 247 | values[0] = screen->white_pixel; 248 | values[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION; 249 | cookie_window = xcb_create_window_checked(c, screen->root_depth, window, screen->root, 20, 200, WIDTH, HEIGHT, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values); 250 | cookie_map = xcb_map_window_checked(c, window); 251 | 252 | /* error managing */ 253 | error = xcb_request_check(c, cookie_window); 254 | if (error) { 255 | fprintf(stderr, "ERROR: can't create window : %d\n", error->error_code); 256 | xcb_disconnect(c); 257 | return -1; 258 | } 259 | error = xcb_request_check(c, cookie_map); 260 | if (error) { 261 | fprintf(stderr, "ERROR: can't map window : %d\n", error->error_code); 262 | xcb_disconnect(c); 263 | return -1; 264 | } 265 | 266 | cursor_set(c, screen, window, 68); 267 | 268 | xcb_flush(c); 269 | 270 | while (1) { 271 | e = xcb_poll_for_event(c); 272 | if (e) { 273 | switch (e->response_type & ~0x80) { 274 | case XCB_EXPOSE:{ 275 | char *text; 276 | 277 | text = "click here to change cursor"; 278 | button_draw(c, screen, window, (WIDTH - 7 * strlen(text)) / 2, (HEIGHT - 16) / 2, text); 279 | 280 | text = "Press ESC key to exit..."; 281 | text_draw(c, screen, window, 10, HEIGHT - 10, text); 282 | break; 283 | } 284 | case XCB_BUTTON_PRESS:{ 285 | xcb_button_press_event_t *ev; 286 | int length; 287 | 288 | ev = (xcb_button_press_event_t *) e; 289 | length = strlen("click here to change cursor"); 290 | 291 | if ((ev->event_x >= (WIDTH - 7 * length) / 2) && (ev->event_x <= ((WIDTH - 7 * length) / 2 + 7 * length + 6)) && (ev->event_y >= (HEIGHT - 16) / 2 - 19) && (ev->event_y <= ((HEIGHT - 16) / 2))) 292 | is_hand = 1 - is_hand; 293 | 294 | is_hand ? cursor_set(c, screen, window, 58) : cursor_set(c, screen, window, 68); 295 | } 296 | case XCB_KEY_RELEASE:{ 297 | xcb_key_release_event_t *ev; 298 | 299 | ev = (xcb_key_release_event_t *) e; 300 | 301 | switch (ev->detail) { 302 | /* ESC */ 303 | case 9: 304 | free(e); 305 | xcb_disconnect(c); 306 | return 0; 307 | } 308 | } 309 | } 310 | free(e); 311 | } 312 | } 313 | 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /examples/xcb/screen.c: -------------------------------------------------------------------------------- 1 | // 99c screen.c -lxcb && ./a.out 2 | 3 | // +build ignore 4 | 5 | // src: https://www.x.org/releases/current/doc/libxcb/tutorial/index.html#screen 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | int main() 12 | { 13 | /* Open the connection to the X server. Use the DISPLAY environment variable */ 14 | 15 | int i, screenNum; 16 | xcb_connection_t *connection = xcb_connect(NULL, &screenNum); 17 | 18 | /* Get the screen whose number is screenNum */ 19 | 20 | const xcb_setup_t *setup = xcb_get_setup(connection); 21 | xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); 22 | 23 | // we want the screen at index screenNum of the iterator 24 | for (i = 0; i < screenNum; ++i) { 25 | xcb_screen_next(&iter); 26 | } 27 | 28 | xcb_screen_t *screen = iter.data; 29 | 30 | /* report */ 31 | 32 | printf("\n"); 33 | printf("Informations of screen %" PRIu32 ":\n", screen->root); 34 | printf(" width.........: %" PRIu16 "\n", screen->width_in_pixels); 35 | printf(" height........: %" PRIu16 "\n", screen->height_in_pixels); 36 | printf(" white pixel...: %" PRIu32 "\n", screen->white_pixel); 37 | printf(" black pixel...: %" PRIu32 "\n", screen->black_pixel); 38 | printf("\n"); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /lib/xau/.gitignore: -------------------------------------------------------------------------------- 1 | libXau-1.0.8.tar.gz 2 | libXau-1.0.8/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /lib/xau/README.md: -------------------------------------------------------------------------------- 1 | # xau 2 | 3 | Package xau installs a 99c version of libXau on your system. 4 | 5 | Run 6 | 7 | $ go generate 8 | 9 | to download and install the package on your system. The package will be installed in '$HOME/.99c'. Currently supported only on Linux. 10 | -------------------------------------------------------------------------------- /lib/xau/generator_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:generate wget --no-clobber https://www.x.org/releases/individual/lib/libXau-1.0.8.tar.gz 6 | //go:generate rm -rf libXau-1.0.8/ 7 | //go:generate tar xzf libXau-1.0.8.tar.gz 8 | //go:generate sh -c "cd libXau-1.0.8/ && ./configure CC=99c --prefix=$HOME/.99c" 9 | //go:generate make -C libXau-1.0.8/ install 10 | 11 | // Package xau installs a 99c version of libXau on your system. 12 | // 13 | // Run 14 | // 15 | // $ go generate 16 | // 17 | // to download and install the package on your system. The package will be 18 | // installed in '$HOME/.99c'. Currently supported only on Linux. 19 | package xau 20 | -------------------------------------------------------------------------------- /lib/xcb/.gitignore: -------------------------------------------------------------------------------- 1 | libxcb-1.12.tar.gz 2 | libxcb-1.12/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /lib/xcb/README.md: -------------------------------------------------------------------------------- 1 | # xcb 2 | 3 | Package xcb installs a 99c version of libxcb on your system. 4 | 5 | Run 6 | 7 | $ go generate 8 | 9 | to download and install the package on your system. The package will be installed in '$HOME/.99c'. Currently supported only on Linux. 10 | -------------------------------------------------------------------------------- /lib/xcb/generator_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:generate wget --no-clobber http://xcb.freedesktop.org/dist/libxcb-1.12.tar.gz 6 | //go:generate rm -rf libxcb-1.12/ 7 | //go:generate tar xzf libxcb-1.12.tar.gz 8 | //go:generate sh -c "cd libxcb-1.12/ && ./configure CC=99c --prefix=$HOME/.99c" 9 | //go:generate make -C libxcb-1.12/ install 10 | 11 | // Package xcb installs a 99c version of libxcb on your system. 12 | // 13 | // Run 14 | // 15 | // $ go generate 16 | // 17 | // to download and install the package on your system. The package will be 18 | // installed in '$HOME/.99c'. Currently supported only on Linux. 19 | package xcb 20 | -------------------------------------------------------------------------------- /libtool.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bufio" 9 | "fmt" 10 | "io" 11 | "os" 12 | "strconv" 13 | "strings" 14 | ) 15 | 16 | var ( 17 | libToolConfigs = map[string]libToolConfig{} 18 | ) 19 | 20 | type libToolConfig map[string]interface{} 21 | 22 | func newLibToolConfig(r io.Reader) (libToolConfig, error) { 23 | s := bufio.NewScanner(r) 24 | c := libToolConfig{} 25 | for s.Scan() { 26 | l := strings.TrimSpace(s.Text()) 27 | if l == "" || strings.HasPrefix(l, "#") { 28 | continue 29 | } 30 | 31 | a := strings.SplitN(l, "=", 2) 32 | if len(a) != 2 { 33 | return nil, fmt.Errorf("invalid libtool config line: %s", l) 34 | } 35 | 36 | nm := strings.TrimSpace(a[0]) 37 | val := strings.TrimSpace(a[1]) 38 | if _, ok := c[nm]; ok { 39 | return nil, fmt.Errorf("duplicate libtool config item: %s", l) 40 | } 41 | 42 | if strings.HasPrefix(val, "'") { 43 | if !strings.HasSuffix(val, "'") { 44 | return nil, fmt.Errorf("invalid libtool config value: %s", l) 45 | } 46 | 47 | c[nm] = val[1 : len(val)-1] 48 | continue 49 | } 50 | 51 | if val == "yes" { 52 | c[nm] = true 53 | continue 54 | } 55 | 56 | if val == "no" { 57 | c[nm] = false 58 | continue 59 | } 60 | 61 | n, err := strconv.ParseUint(val, 10, 31) 62 | if err == nil { 63 | c[nm] = int(n) 64 | continue 65 | } 66 | 67 | return nil, fmt.Errorf("invalid libtool config line: %s", l) 68 | } 69 | if err := s.Err(); err != nil { 70 | return nil, err 71 | } 72 | 73 | return c, nil 74 | } 75 | 76 | func newLibToolConfigFile(fn string) (libToolConfig, error) { 77 | if x, ok := libToolConfigs[fn]; ok { 78 | return x, nil 79 | } 80 | 81 | f, err := os.Open(fn) 82 | if err != nil { 83 | return nil, err 84 | } 85 | 86 | defer f.Close() 87 | 88 | c, err := newLibToolConfig(f) 89 | if err != nil { 90 | return nil, err 91 | } 92 | 93 | libToolConfigs[fn] = c 94 | return c, nil 95 | } 96 | 97 | func (c libToolConfig) dependencyLibs() ([]string, error) { 98 | var r []string 99 | rq, ok := c["dependency_libs"] 100 | if !ok { 101 | return nil, nil 102 | } 103 | 104 | s, ok := rq.(string) 105 | if !ok { 106 | return nil, fmt.Errorf("invalid dependency_libs value: %T(%#v)", rq, rq) 107 | } 108 | 109 | s = strings.TrimSpace(s) 110 | a := strings.Split(s, " ") 111 | for _, v := range a { 112 | v = strings.TrimSpace(v) 113 | if v == "" { 114 | continue 115 | } 116 | 117 | if v == "-l" || !strings.HasPrefix(v, "-l") { 118 | return nil, fmt.Errorf("invalid dependency_libs value: %v", s) 119 | } 120 | 121 | r = append(r, v[2:]) 122 | } 123 | return r, nil 124 | } 125 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The 99c Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:generate go get -u 6 | //go:generate go install -tags virtual.profile ./99prof 7 | //go:generate go install -tags virtual.strace ./99strace 8 | //go:generate go install -tags virtual.trace ./99trace 9 | //go:generate go install ./99dump ./99nm ./99run 10 | 11 | package main 12 | 13 | import ( 14 | "bufio" 15 | "fmt" 16 | "go/scanner" 17 | "go/token" 18 | "os" 19 | "path/filepath" 20 | "runtime" 21 | "runtime/debug" 22 | "strings" 23 | 24 | "github.com/cznic/cc" 25 | "github.com/cznic/ccir" 26 | "github.com/cznic/ir" 27 | "github.com/cznic/strutil" 28 | "github.com/cznic/virtual" 29 | "github.com/cznic/xc" 30 | ) 31 | 32 | func exit(code int, msg string, arg ...interface{}) { 33 | msg = strings.TrimSpace(msg) 34 | if msg != "" { 35 | fmt.Fprintf(os.Stderr, os.Args[0]+": "+msg+"\n", arg...) 36 | } 37 | os.Stderr.Sync() 38 | os.Exit(code) 39 | } 40 | 41 | func main() { 42 | if s := os.Getenv("DIAG99C"); strings.Contains(","+s+",", ",os-args,") { 43 | fmt.Fprintf(os.Stderr, "%v\n", os.Args) 44 | } 45 | 46 | defer func() { 47 | if err := recover(); err != nil { 48 | exit(1, "PANIC: %v\n%s", err, debug.Stack()) 49 | } 50 | }() 51 | 52 | t := newTask() 53 | t.args.getopt(os.Args) 54 | if err := t.main(); err != nil { 55 | switch x := err.(type) { 56 | case scanner.ErrorList: 57 | scanner.PrintError(os.Stderr, x) 58 | os.Exit(1) 59 | default: 60 | exit(1, "%v", err) 61 | } 62 | } 63 | } 64 | 65 | type testHooks struct { 66 | bin **virtual.Binary 67 | obj *ir.Objects 68 | } 69 | 70 | type args struct { 71 | D []string // -D 72 | E bool // -E 73 | I []string // -I 74 | L []string // -L 75 | O string // -O 76 | W string // -W 77 | args []string // Non flag arguments in order of appearance. 78 | c bool // -c 79 | g bool // -g 80 | hooks testHooks 81 | l []string // -l 82 | lib bool // -99lib 83 | o string // -o 84 | opts []cc.Opt // cc flags 85 | rdynamic bool // -rdynamic 86 | shared bool // -shared 87 | } 88 | 89 | func (a *args) extra(name string) cc.Opt { 90 | switch name { 91 | case "AlignOf": 92 | return cc.EnableAlignOf() 93 | case "AlternateKeywords": 94 | return cc.EnableAlternateKeywords() 95 | case "AnonymousStructFields": 96 | return cc.EnableAnonymousStructFields() 97 | case "Asm": 98 | return cc.EnableAsm() 99 | case "BuiltinClassifyType": 100 | return cc.EnableBuiltinClassifyType() 101 | case "BuiltinConstantP": 102 | return cc.EnableBuiltinConstantP() 103 | case "ComputedGotos": 104 | return cc.EnableComputedGotos() 105 | case "DlrInIdentifiers": 106 | return cc.EnableDlrInIdentifiers() 107 | case "EmptyDeclarations": 108 | return cc.EnableEmptyDeclarations() 109 | case "EmptyDefine": 110 | return cc.EnableEmptyDefine() 111 | case "EmptyStructs": 112 | return cc.EnableEmptyStructs() 113 | case "ImaginarySuffix": 114 | return cc.EnableImaginarySuffix() 115 | case "ImplicitFuncDef": 116 | return cc.EnableImplicitFuncDef() 117 | case "ImplicitIntType": 118 | return cc.EnableImplicitIntType() 119 | case "IncludeNext": 120 | return cc.EnableIncludeNext() 121 | case "LegacyDesignators": 122 | return cc.EnableLegacyDesignators() 123 | case "NonConstStaticInitExpressions": 124 | return cc.EnableNonConstStaticInitExpressions() 125 | case "Noreturn": 126 | return cc.EnableNoreturn() 127 | case "OmitConditionalOperand": 128 | return cc.EnableOmitConditionalOperand() 129 | case "OmitFuncArgTypes": 130 | return cc.EnableOmitFuncArgTypes() 131 | case "OmitFuncRetType": 132 | return cc.EnableOmitFuncRetType() 133 | case "ParenthesizedCompoundStatemen": 134 | return cc.EnableParenthesizedCompoundStatemen() 135 | case "StaticAssert": 136 | return cc.EnableStaticAssert() 137 | case "TypeOf": 138 | return cc.EnableTypeOf() 139 | case "UndefExtraTokens": 140 | return cc.EnableUndefExtraTokens() 141 | case "UnsignedEnums": 142 | return cc.EnableUnsignedEnums() 143 | case "WideBitFieldTypes": 144 | return cc.EnableWideBitFieldTypes() 145 | case "WideEnumValues": 146 | return cc.EnableWideEnumValues() 147 | } 148 | exit(2, "unknown -99extra argument: %s", name) 149 | panic("unreachable") 150 | } 151 | 152 | func (a *args) getopt(args []string) { 153 | args = args[1:] 154 | for i, arg := range args { 155 | switch { 156 | case arg == "-99lib": 157 | a.lib = true 158 | case strings.HasPrefix(arg, "-D"): 159 | if arg == "-D" { 160 | break 161 | } 162 | 163 | arg = arg[2:] 164 | p := strings.SplitN(arg, "=", 2) 165 | if len(p) == 1 { 166 | p = append(p, "1") 167 | } 168 | a.D = append(a.D, fmt.Sprintf("#define %s %s", p[0], p[1])) 169 | case arg == "-E": 170 | a.E = true 171 | case strings.HasPrefix(arg, "-I"): 172 | if arg == "-I" { 173 | break 174 | } 175 | 176 | arg = arg[2:] 177 | a.I = append(a.I, arg) 178 | case strings.HasPrefix(arg, "-L"): 179 | if arg == "-L" { 180 | break 181 | } 182 | 183 | arg = arg[2:] 184 | a.L = append(a.L, arg) 185 | case strings.HasPrefix(arg, "-O"): 186 | a.O = arg[2:] 187 | case strings.HasPrefix(arg, "-W"): 188 | a.W = arg[2:] 189 | case arg == "-ansi": 190 | // nop 191 | case arg == "-c": 192 | a.c = true 193 | case arg == "-99extra": 194 | if i+1 >= len(args) { 195 | exit(2, "missing -99extra argument") 196 | } 197 | 198 | a.opts = append(a.opts, a.extra(args[i+1])) 199 | args[i+1] = "" 200 | case arg == "-g": 201 | a.g = true 202 | case strings.HasPrefix(arg, "-l"): 203 | if arg == "-l" { 204 | break 205 | } 206 | 207 | arg = arg[2:] 208 | a.l = append(a.l, arg) 209 | case arg == "-o": 210 | if i+1 >= len(args) { 211 | exit(2, "missing -o argument") 212 | } 213 | 214 | a.o = args[i+1] 215 | args[i+1] = "" 216 | case arg == "-pedantic": 217 | // nop 218 | case arg == "-pthread": 219 | //TODO 220 | case arg == "-rdynamic": 221 | a.rdynamic = true 222 | case arg == "-rpath": 223 | if i+1 >= len(args) { 224 | exit(2, "missing -rptah argument") 225 | } 226 | 227 | a.o = args[i+1] 228 | args[i+1] = "" 229 | case arg == "-shared": 230 | a.shared = true 231 | //TODO 232 | case arg == "-soname": 233 | if i+1 >= len(args) { 234 | exit(2, "missing -soname argument") 235 | } 236 | 237 | //TODO 238 | args[i+1] = "" 239 | case strings.HasPrefix(arg, "-"): 240 | s := "" 241 | if arg != "-h" { 242 | s = fmt.Sprintf("%v unknown flag: %s\n", os.Args, arg) 243 | } 244 | exit(2, `%sFlags: 245 | -99lib 246 | Library link mode. 247 | -Dname 248 | Equivalent to inserting '#define name 1' at the start of the 249 | translation unit. 250 | -Dname=definition 251 | Equivalent to inserting '#define name definition' at the start of the 252 | translation unit. 253 | -E Copy C-language source files to standard output, executing all 254 | preprocessor directives; no compilation shall be performed. If any 255 | operand is not a text file, the effects are unspecified. 256 | -Ipath 257 | Add path to the include files search paths. 258 | -Lpath 259 | Add path to search paths for -l. 260 | -Olevel 261 | Optimization setting, ignored. 262 | -Wwarn 263 | Warning level, ignored. 264 | -ansi 265 | Ignored. 266 | -c Suppress the link-edit phase of the compilation, and do not 267 | remove any object files that are produced. 268 | -g Produce debugging information, ignored. 269 | -l 270 | Link with lib. 271 | -o pathname 272 | Use the specified pathname, instead of the default a.out, for 273 | the executable file produced. If the -o option is present with 274 | -c or -E, the result is unspecified. 275 | -pedantic 276 | Ignored. 277 | -pthread 278 | Ignored. (TODO) 279 | -rdynamic 280 | Ignored. (TODO) 281 | -rpath pathname 282 | Ignored. (TODO) 283 | -shared 284 | Link mode shared library. 285 | -soname arg 286 | Ignored. (TODO) 287 | -99extra flag 288 | Extra cc flags: 289 | AlignOf 290 | AlternateKeywords 291 | AnonymousStructFields 292 | Asm 293 | BuiltinClassifyType 294 | BuiltinConstantP 295 | ComputedGotos 296 | DlrInIdentifiers 297 | EmptyDeclarations 298 | EmptyDefine 299 | EmptyStructs 300 | ImaginarySuffix 301 | ImplicitFuncDef 302 | ImplicitIntType 303 | IncludeNext 304 | LegacyDesignators 305 | NonConstStaticInitExpressions 306 | Noreturn 307 | OmitConditionalOperand 308 | OmitFuncArgTypes 309 | OmitFuncRetType 310 | ParenthesizedCompoundStatemen 311 | StaticAssert 312 | TypeOf 313 | UndefExtraTokens 314 | UnsignedEnums 315 | WideBitFieldTypes 316 | WideEnumValues`, 317 | s) 318 | default: 319 | if arg != "" { 320 | a.args = append(a.args, arg) 321 | } 322 | } 323 | } 324 | } 325 | 326 | type task struct { 327 | args args 328 | afiles []string 329 | cfiles []string 330 | ofiles []string 331 | } 332 | 333 | func fatalError(msg string, arg ...interface{}) error { 334 | return fmt.Errorf("fatal error: %s", fmt.Sprintf(msg, arg...)) 335 | } 336 | 337 | func clean(a []string) (r []string) { 338 | m := map[string]struct{}{} 339 | for _, v := range a { 340 | if _, ok := m[v]; !ok { 341 | r = append(r, v) 342 | m[v] = struct{}{} 343 | } 344 | } 345 | return r 346 | } 347 | 348 | func join(a ...interface{}) (r []string) { 349 | for _, v := range a { 350 | switch x := v.(type) { 351 | case string: 352 | r = append(r, x) 353 | case []string: 354 | r = append(r, x...) 355 | default: 356 | panic("internal error") 357 | } 358 | } 359 | return clean(r) 360 | } 361 | 362 | func newTask() *task { return &task{} } 363 | 364 | func (t *task) main() error { 365 | // -I dir 366 | // -iquote dir 367 | // -isystem dir 368 | // -idirafter dir 369 | // 370 | // Add the directory dir to the list of directories to be searched for 371 | // header files during preprocessing. See Search Path. If dir begins 372 | // with ‘=’ or $SYSROOT, then the ‘=’ or $SYSROOT is replaced by the 373 | // sysroot prefix; see --sysroot and -isysroot. 374 | // 375 | // Directories specified with -iquote apply only to the quote form of 376 | // the directive, #include "file". Directories specified with -I, 377 | // -isystem, or -idirafter apply to lookup for both the #include "file" 378 | // and #include directives. 379 | // 380 | // You can specify any number or combination of these options on the 381 | // command line to search for header files in several directories. The 382 | // lookup order is as follows: 383 | // 384 | // 1. For the quote form of the include directive, the directory of the 385 | // current file is searched first. 386 | // 387 | // 2. For the quote form of the include directive, the directories 388 | // specified by -iquote options are searched in left-to-right order, as 389 | // they appear on the command line. 390 | // 391 | // 3. Directories specified with -I options are scanned in 392 | // left-to-right order. 393 | // 394 | // 4. Directories specified with -isystem options are scanned in 395 | // left-to-right order. 396 | // 397 | // 5. Standard system directories are scanned. 398 | // 399 | // 6. Directories specified with -idirafter options are scanned in 400 | // left-to-right order. 401 | // 402 | // You can use -I to override a system header file, substituting your 403 | // own version, since these directories are searched before the 404 | // standard system header file directories. However, you should not 405 | // use this option to add directories that contain vendor-supplied 406 | // system header files; use -isystem for that. 407 | // 408 | // The -isystem and -idirafter options also mark the directory as a 409 | // system directory, so that it gets the same special treatment that is 410 | // applied to the standard system directories. See System Headers. 411 | // 412 | // If a standard system include directory, or a directory specified 413 | // with -isystem, is also specified with -I, the -I option is ignored. 414 | // The directory is still searched but as a system directory at its 415 | // normal position in the system include chain. This is to ensure that 416 | // GCC’s procedure to fix buggy system headers and the ordering for the 417 | // #include_next directive are not inadvertently changed. If you really 418 | // need to change the search order for system directories, use the 419 | // -nostdinc and/or -isystem options. See System Headers. 420 | // 421 | // src: https://gcc.gnu.org/onlinedocs/cpp/Invocation.html#Invocation 422 | includes := join( 423 | "@", // 1. 424 | t.args.I, // 3. 425 | ccir.LibcIncludePath, // 5. 426 | ) 427 | 428 | // GCC order of items would be 3., 5. 429 | sysIncludes := join( 430 | ccir.LibcIncludePath, // 5. 431 | t.args.I, // 3. 432 | ) 433 | 434 | if h := strutil.Homepath(); h != "" { 435 | p := filepath.Join(h, ".99c") 436 | fi, err := os.Stat(p) 437 | if err == nil && fi.IsDir() { 438 | sysIncludes = append(sysIncludes, filepath.Join(p, "include")) 439 | t.args.L = append(t.args.I, filepath.Join(p, "lib")) 440 | } 441 | } 442 | 443 | //TODO- fmt.Println("includes", includes) 444 | //TODO- fmt.Println("sysIncludes", sysIncludes) 445 | 446 | if len(t.args.args) == 0 { 447 | return fatalError("no input files") 448 | } 449 | 450 | if t.args.o != "" && (t.args.c || t.args.E) && len(t.args.args) > 1 { 451 | exit(2, "cannot specify -o with -c or -E with multiple files") 452 | } 453 | 454 | lsearch := append([]string{"."}, t.args.L...) 455 | lm := map[string]struct{}{} 456 | for i := 0; i < len(t.args.l); i++ { 457 | v := t.args.l[i] 458 | if _, ok := lm[v]; ok { 459 | continue 460 | } 461 | 462 | lm[v] = struct{}{} 463 | for _, d := range lsearch { 464 | fn := filepath.Join(d, fmt.Sprintf("lib%s.so", v)) 465 | _, err := os.Stat(fn) 466 | if err != nil { 467 | if !os.IsNotExist(err) { 468 | return fatalError("%v", err) 469 | } 470 | 471 | continue 472 | } 473 | 474 | t.ofiles = append(t.ofiles, fn) 475 | la := fn[:len(fn)-len(filepath.Ext(fn))] + ".la" 476 | c, err := newLibToolConfigFile(la) 477 | if err != nil { 478 | return fatalError("%v", err) 479 | } 480 | 481 | deps, err := c.dependencyLibs() 482 | if err != nil { 483 | return fatalError("%s: %v", la, err) 484 | } 485 | 486 | t.args.l = append(t.args.l, deps...) 487 | break 488 | } 489 | } 490 | 491 | for _, arg := range t.args.args { 492 | switch filepath.Ext(arg) { 493 | case ".a": 494 | t.afiles = append(t.afiles, arg) 495 | case ".c", ".h": 496 | t.cfiles = append(t.cfiles, arg) 497 | case ".o", ".so": 498 | t.ofiles = append(t.ofiles, arg) 499 | default: 500 | return fatalError("unrecognized file type: %v", arg) 501 | } 502 | } 503 | 504 | switch { 505 | case t.args.E: 506 | o := os.Stdout 507 | if fn := t.args.o; fn != "" { 508 | var err error 509 | if o, err = os.Create(fn); err != nil { 510 | return fatalError("%v", err) 511 | } 512 | } 513 | out := bufio.NewWriter(o) 514 | 515 | defer out.Flush() 516 | 517 | var lpos token.Position 518 | opts := []cc.Opt{ 519 | cc.Mode99c(), 520 | cc.IncludePaths(includes), 521 | cc.SysIncludePaths(sysIncludes), 522 | cc.AllowCompatibleTypedefRedefinitions(), 523 | cc.EnableDefineOmitCommaBeforeDDD(), 524 | cc.Cpp(func(toks []xc.Token) { 525 | if len(toks) != 0 { 526 | p := toks[0].Position() 527 | if p.Filename != lpos.Filename { 528 | fmt.Fprintf(out, "# %d %q\n", p.Line, p.Filename) 529 | } 530 | lpos = p 531 | } 532 | for _, v := range toks { 533 | if s := strings.TrimSpace(cc.TokSrc(v)); s != "" { 534 | fmt.Fprintf(out, "%v ", s) 535 | } 536 | } 537 | fmt.Fprintln(out) 538 | }), 539 | } 540 | opts = append(opts, t.args.opts...) 541 | for _, v := range t.cfiles { 542 | model, err := ccir.NewModel() 543 | if err != nil { 544 | return fatalError("%v", err) 545 | } 546 | 547 | if _, err := cc.Parse( 548 | fmt.Sprintf(` 549 | %s 550 | #define __arch__ %s 551 | #define __os__ %s 552 | #include 553 | `, strings.Join(t.args.D, "\n"), runtime.GOARCH, runtime.GOOS), 554 | []string{v}, 555 | model, 556 | opts..., 557 | ); err != nil { 558 | return err 559 | } 560 | } 561 | return nil 562 | } 563 | 564 | var obj ir.Objects 565 | for _, fn := range t.ofiles { 566 | f, err := os.Open(fn) 567 | if err != nil { 568 | return fatalError("%v", err) 569 | } 570 | 571 | r := bufio.NewReader(f) 572 | var o ir.Objects 573 | if _, err := o.ReadFrom(r); err != nil { 574 | return fatalError("%v", err) 575 | } 576 | 577 | obj = append(obj, o...) 578 | } 579 | for _, fn := range t.afiles { 580 | a, err := archive(fn) 581 | if err != nil { 582 | return fatalError("%v", err) 583 | } 584 | 585 | obj = append(obj, a...) 586 | } 587 | 588 | switch { 589 | case t.args.c: 590 | opts := []cc.Opt{ 591 | cc.Mode99c(), 592 | cc.IncludePaths(includes), 593 | cc.SysIncludePaths(sysIncludes), 594 | cc.AllowCompatibleTypedefRedefinitions(), 595 | cc.EnableDefineOmitCommaBeforeDDD(), 596 | } 597 | opts = append(opts, t.args.opts...) 598 | for _, arg := range t.cfiles { 599 | model, err := ccir.NewModel() 600 | if err != nil { 601 | return fatalError("%v", err) 602 | } 603 | 604 | tu, err := cc.Parse( 605 | fmt.Sprintf(` 606 | %s 607 | #define __arch__ %s 608 | #define __os__ %s 609 | #include 610 | `, strings.Join(t.args.D, "\n"), runtime.GOARCH, runtime.GOOS), 611 | []string{arg}, 612 | model, 613 | opts..., 614 | ) 615 | if err != nil { 616 | return err 617 | } 618 | 619 | o, err := ccir.New(tu) 620 | if err != nil { 621 | return err 622 | } 623 | 624 | if p := t.args.hooks.obj; p != nil { 625 | *p = ir.Objects{o} 626 | } 627 | fn := filepath.Base(arg[:len(arg)-len(filepath.Ext(arg))]) + ".o" 628 | f, err := os.Create(fn) 629 | if err != nil { 630 | return err 631 | } 632 | 633 | w := bufio.NewWriter(f) 634 | if _, err := (ir.Objects{o}).WriteTo(w); err != nil { 635 | return err 636 | } 637 | 638 | if err := w.Flush(); err != nil { 639 | return err 640 | } 641 | 642 | if err := f.Close(); err != nil { 643 | return err 644 | } 645 | } 646 | return nil 647 | default: 648 | fn := t.args.o 649 | if fn == "" { 650 | fn = "a.out" 651 | } 652 | opts := []cc.Opt{ 653 | cc.Mode99c(), 654 | cc.IncludePaths(includes), 655 | cc.SysIncludePaths(sysIncludes), 656 | cc.AllowCompatibleTypedefRedefinitions(), 657 | cc.EnableDefineOmitCommaBeforeDDD(), 658 | } 659 | opts = append(opts, t.args.opts...) 660 | 661 | for _, v := range append(t.cfiles, ccir.CRT0Path) { 662 | model, err := ccir.NewModel() 663 | if err != nil { 664 | return fatalError("%v", err) 665 | } 666 | 667 | tu, err := cc.Parse( 668 | fmt.Sprintf(` 669 | %s 670 | #define __arch__ %s 671 | #define __os__ %s 672 | #include 673 | `, strings.Join(t.args.D, "\n"), runtime.GOARCH, runtime.GOOS), 674 | []string{v}, 675 | model, 676 | opts..., 677 | ) 678 | if err != nil { 679 | return err 680 | } 681 | 682 | o, err := ccir.New(tu) 683 | if err != nil { 684 | return err 685 | } 686 | 687 | obj = append(obj, o) 688 | } 689 | 690 | var out ir.Objects 691 | switch { 692 | case t.args.shared: 693 | out = append(out, obj...) 694 | f, err := os.Create(fn) 695 | if err != nil { 696 | return err 697 | } 698 | 699 | _, err = out.WriteTo(f) 700 | return err 701 | case t.args.lib: 702 | o, err := ir.LinkLib(obj...) 703 | if err != nil { 704 | return err 705 | } 706 | 707 | out = ir.Objects{o} 708 | default: 709 | for _, v := range obj { 710 | for _, o := range v { 711 | if err := o.Verify(); err != nil { 712 | return err 713 | } 714 | } 715 | } 716 | o, err := ir.LinkMain(obj...) 717 | if err != nil { 718 | return err 719 | } 720 | 721 | out = ir.Objects{o} 722 | } 723 | if len(out) != 1 { 724 | panic("internal error") 725 | } 726 | 727 | bin, err := virtual.LoadMain(out[0]) 728 | if err != nil { 729 | return err 730 | } 731 | 732 | if p := t.args.hooks.bin; p != nil { 733 | *p = bin 734 | } 735 | f, err := os.Create(fn) 736 | if err != nil { 737 | return err 738 | } 739 | 740 | if runtime.GOOS == "linux" { 741 | f.WriteString("#!/usr/bin/env 99run\n") 742 | } 743 | 744 | if !t.args.g { 745 | bin.Functions = nil 746 | bin.Lines = nil 747 | if !t.args.lib { 748 | start, ok := bin.LookupFunction("_start") 749 | bin.Sym = nil 750 | if ok { 751 | bin.Sym = map[ir.NameID]int{ir.NameID(xc.Dict.SID("_start")): start} 752 | } 753 | } 754 | } 755 | if _, err := bin.WriteTo(f); err != nil { 756 | return err 757 | } 758 | 759 | if err := f.Close(); err != nil { 760 | return err 761 | } 762 | 763 | fi, err := os.Stat(fn) 764 | if err != nil { 765 | return err 766 | } 767 | 768 | m := fi.Mode() 769 | for k, b := os.FileMode(0400), os.FileMode(0100); k != 0; k, b = k>>3, b>>3 { 770 | if m&k != 0 { 771 | m |= b 772 | } 773 | } 774 | 775 | return os.Chmod(fn, m) 776 | } 777 | } 778 | -------------------------------------------------------------------------------- /testdata/issue4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int fib(int n) 5 | { 6 | switch (n) { 7 | case 0: 8 | return 0; 9 | case 1: 10 | return 1; 11 | default: 12 | return fib(n - 1) + fib(n - 2); 13 | } 14 | } 15 | 16 | int main(int argc, char **argv) 17 | { 18 | if (argc != 2) { 19 | return 2; 20 | } 21 | 22 | int n = atoi(argv[1]); 23 | if (n <= 0 || n > 40) { 24 | return 1; 25 | } 26 | 27 | printf("%i\n", fib(n)); 28 | } 29 | -------------------------------------------------------------------------------- /testdata/libXau.la: -------------------------------------------------------------------------------- 1 | # libXau.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.2 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='libXau.so.6' 9 | 10 | # Names of this library. 11 | library_names='libXau.so.6.0.0 libXau.so.6 libXau.so' 12 | 13 | # The name of the static archive. 14 | old_library='libXau.a' 15 | 16 | # Linker flags that can not go in dependency_libs. 17 | inherited_linker_flags='' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs='' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for libXau. 26 | current=6 27 | age=0 28 | revision=0 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=no 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/home/user/.99c/lib' 42 | -------------------------------------------------------------------------------- /testdata/libxcb.la: -------------------------------------------------------------------------------- 1 | # libxcb.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-0.1 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='libxcb.so.1' 9 | 10 | # Names of this library. 11 | library_names='libxcb.so.1.1.0 libxcb.so.1 libxcb.so' 12 | 13 | # The name of the static archive. 14 | old_library='libxcb.a' 15 | 16 | # Linker flags that cannot go in dependency_libs. 17 | inherited_linker_flags='' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs=' -lXau' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for libxcb. 26 | current=2 27 | age=1 28 | revision=0 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=no 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/home/user/.99c/lib' 42 | --------------------------------------------------------------------------------