This reverts the crap from an unknown committer "OpenCode[AI]", that added an extension to TinyCC, which is incompatible to the C standard and not available in any other mainstream C compiler: * Revert "No More ; needed" This reverts commit 6547ea47d66a4d382c9c2cfc317426d8a3a5734e * Revert "Add AGENTS.md" This reverts commit 898f496dc9d68e85a81daa836009930a975ea71a. This also reverts a regression fix by "Zuhaitz.dev", which fixed a small part of the OpenCode-AI chaos: * Revert "tccgen: Fix optional semicolon regression" This reverts commit 169628a6abf2bf32a9f73a7db5b4fd3ea973d97a -- Regards ... Detlef
Unified · Split
| @@ -1,54 +0,0 @@ | |||
| 1 | # TinyCC (Tiny C Compiler) | ||
| 2 | |||
| 3 | ## Build & Test | ||
| 4 | |||
| 5 | ```sh | ||
| 6 | ./configure && make && make test | ||
| 7 | ``` | ||
| 8 | |||
| 9 | - `make` builds `tcc` + `libtcc.a` + `libtcc1.a`. `libtcc1.a` is built by a recursive `make -C lib`. | ||
| 10 | - `make test` runs the full test suite (`tests/`), ~2 minutes. | ||
| 11 | - Run a single tests2 test: `make tests2.37` (run) or `make tests2.37+` (update .expect). | ||
| 12 | - Run a single tests/pp test: `make testspp.17`. | ||
| 13 | - Sanitizer tests: `make sani-test`, `make sani-tests2.37`, `make sani-testspp.17`. | ||
| 14 | - Coverage tests: `make tcov-test`, `make tcov-tests2.37`, `make tcov-testspp.17`. | ||
| 15 | - Test installed tcc: `make test-install`. | ||
| 16 | |||
| 17 | ## Architecture | ||
| 18 | |||
| 19 | - **Single-file-ish compiler**: tcc compiles itself (or can be bootstrapped). `tcc.c` is the main entrypoint; `tccpp.c` handles preprocessing, `tccgen.c` handles code generation, `tccelf.c` handles ELF linking, `tccasm.c` handles inline asm, `tccrun.c` handles runtime execution, `tccdbg.c` handles debug info. | ||
| 20 | - **Backend files per architecture**: `i386-gen.c`, `x86_64-gen.c`, `arm-gen.c`, `arm64-gen.c`, `riscv64-gen.c`, `c67-gen.c`, plus corresponding asm/link files. | ||
| 21 | - **Generated file**: `include/tccdefs.h` is converted to `tccdefs_.h` by `c2str.exe` (built from `conftest.c`). Always exists after first `make`. | ||
| 22 | - **Cross-compilers**: `make cross` builds all cross-compilers; `make cross-i386`, `make cross-x86_64`, etc. for one target. `make CROSS_TARGET=i386 ONE_SOURCE=yes` for single-object cross build. | ||
| 23 | - **`ONE_SOURCE=yes`**: builds tcc as a single object file (default for cross-compilers, native uses separate objects). | ||
| 24 | |||
| 25 | ## Coding Style | ||
| 26 | |||
| 27 | - **C90** with these pre-existing non-C90 features: `long long`, `inline`, `//` comments, unnamed struct/union fields, empty macro arguments, assignment between function pointer and `void *`. | ||
| 28 | - **Indentation**: 4 spaces for most files; some files (e.g. `i386-gen.c`) use 2 spaces for deep nesting. | ||
| 29 | - **Do not reformat** existing code unless the change is the primary purpose. | ||
| 30 | - Remove tabs and trailing whitespace from modified lines. | ||
| 31 | - Check with `./configure --extra-cflags="-std=c90 -Wpedantic"`. | ||
| 32 | |||
| 33 | ## Test Quirks | ||
| 34 | |||
| 35 | - `test.ref` (reference output) is generated from `tcctest.c` using gcc: `(cd tests && gcc -I.. tcctest.c && valgrind -q ./a.out > test.ref)` then `make test TCC="valgrind -q --leak-check=full $(pwd)/tcc -B$(pwd) -I$(pwd)"`. | ||
| 36 | - VLA tests (`79_vla_continue`) produce expected invalid reads under Valgrind. | ||
| 37 | - tests2 skip list is in `tests/tests2/Makefile` (architecture- and config-specific skips). | ||
| 38 | - Some tests need special flags (see `FLAGS =` assignments in `tests/tests2/Makefile`). | ||
| 39 | - Bound-check tests (`-b` flag) are skipped when `CONFIG_bcheck=no`. | ||
| 40 | - `.expect` files are generated with gcc by default; some use TCC (flagged with `GEN-TCC`). | ||
| 41 | |||
| 42 | ## Language Extension: Optional Semicolons | ||
| 43 | |||
| 44 | Semicolons are optional after most statements and declarations: | ||
| 45 | - `return`, `break`, `continue`, `goto`, expression statements | ||
| 46 | - `do-while` trailing semicolon | ||
| 47 | - Variable declarations | ||
| 48 | |||
| 49 | Semicolons are still **required** for: | ||
| 50 | - `for()` loop init/condition/increment sections (e.g., `for(i=0; i<n; i++)`) | ||
| 51 | - Old-style function parameter declarations | ||
| 52 | - Struct/enum member declarations | ||
| 53 | |||
| 54 | The `skip(';')` function in `tccpp.c:100` errors if token doesn't match. Use `if (tok == ';') next();` instead to make semicolons optional. | ||
| @@ -7205,7 +7205,7 @@ again: · 7204 unmodified lines | |||
| 7205 | label_push(&local_label_stack, tok, LABEL_DECLARED); | 7205 | label_push(&local_label_stack, tok, LABEL_DECLARED); |
| 7206 | next(); | 7206 | next(); |
| 7207 | } while (tok == ','); | 7207 | } while (tok == ','); |
| 7208 | if (tok == ';') next(); | 7208 | skip(';'); |
| 7209 | } | 7209 | } |
| 7210 | 7210 | ||
| 7211 | while (tok != '}') { | 7211 | while (tok != '}') { |
| @@ -7241,7 +7241,7 @@ again: · 29 unmodified lines | |||
| 7241 | leave_scope(root_scope); | 7241 | leave_scope(root_scope); |
| 7242 | if (b) | 7242 | if (b) |
| 7243 | gfunc_return(&func_vt); | 7243 | gfunc_return(&func_vt); |
| 7244 | if (tok == ';') next(); | 7244 | skip(';'); |
| 7245 | /* jump unless last stmt in top-level block */ | 7245 | /* jump unless last stmt in top-level block */ |
| 7246 | if (tok != '}' || local_scope != 1) | 7246 | if (tok != '}' || local_scope != 1) |
| 7247 | rsym = gjmp(rsym); | 7247 | rsym = gjmp(rsym); |
| @@ -7258,7 +7258,7 @@ again: · 10 unmodified lines | |||
| 7258 | else | 7258 | else |
| 7259 | leave_scope(loop_scope); | 7259 | leave_scope(loop_scope); |
| 7260 | *cur_scope->bsym = gjmp(*cur_scope->bsym); | 7260 | *cur_scope->bsym = gjmp(*cur_scope->bsym); |
| 7261 | if (tok == ';') next(); | 7261 | skip(';'); |
| 7262 | 7262 | ||
| 7263 | } else if (t == TOK_CONTINUE) { | 7263 | } else if (t == TOK_CONTINUE) { |
| 7264 | /* compute jump */ | 7264 | /* compute jump */ |
| @@ -7266,7 +7266,7 @@ again: · 1 unmodified line | |||
| 7266 | tcc_error("cannot continue"); | 7266 | tcc_error("cannot continue"); |
| 7267 | leave_scope(loop_scope); | 7267 | leave_scope(loop_scope); |
| 7268 | *cur_scope->csym = gjmp(*cur_scope->csym); | 7268 | *cur_scope->csym = gjmp(*cur_scope->csym); |
| 7269 | if (tok == ';') next(); | 7269 | skip(';'); |
| 7270 | 7270 | ||
| 7271 | } else if (t == TOK_FOR) { | 7271 | } else if (t == TOK_FOR) { |
| 7272 | new_scope(&o); | 7272 | new_scope(&o); |
| @@ -7314,7 +7314,7 @@ again: · 41 unmodified lines | |||
| 7314 | gexpr(); | 7314 | gexpr(); |
| 7315 | c = gvtst(0, 0); | 7315 | c = gvtst(0, 0); |
| 7316 | skip(')'); | 7316 | skip(')'); |
| 7317 | if (tok == ';') next(); | 7317 | skip(';'); |
| 7318 | gsym_addr(c, d); | 7318 | gsym_addr(c, d); |
| 7319 | gsym(a); | 7319 | gsym(a); |
| 7320 | prev_scope_s(&o); | 7320 | prev_scope_s(&o); |
| @@ -7426,7 +7426,7 @@ again: · 105 unmodified lines | |||
| 7426 | } else { | 7426 | } else { |
| 7427 | expect("label identifier"); | 7427 | expect("label identifier"); |
| 7428 | } | 7428 | } |
| 7429 | if (tok == ';') next(); | 7429 | skip(';'); |
| 7430 | 7430 | ||
| 7431 | } else if (t == TOK_ASM1 || t == TOK_ASM2 || t == TOK_ASM3) { | 7431 | } else if (t == TOK_ASM1 || t == TOK_ASM2 || t == TOK_ASM3) { |
| 7432 | asm_instr(); | 7432 | asm_instr(); |
| @@ -7481,7 +7481,7 @@ again: · 48 unmodified lines | |||
| 7481 | gexpr(); | 7481 | gexpr(); |
| 7482 | vpop(); | 7482 | vpop(); |
| 7483 | } | 7483 | } |
| 7484 | if (tok == ';') next(); | 7484 | skip(';'); |
| 7485 | } | 7485 | } |
| 7486 | } | 7486 | } |
| 7487 | } | 7487 | } |
| @@ -8637,7 +8637,7 @@ static void do_Static_assert(void) · 1149 unmodified lines | |||
| 8637 | skip(')'); | 8637 | skip(')'); |
| 8638 | if (c == 0) | 8638 | if (c == 0) |
| 8639 | tcc_error("%s", msg); | 8639 | tcc_error("%s", msg); |
| 8640 | if (tok == ';') next(); | 8640 | skip(';'); |
| 8641 | } | 8641 | } |
| 8642 | 8642 | ||
| 8643 | #ifdef TCC_TARGET_PE | 8643 | #ifdef TCC_TARGET_PE |
| @@ -8904,10 +8904,7 @@ static int decl(int l) · 260 unmodified lines | |||
| 8904 | if (tok != ',') { | 8904 | if (tok != ',') { |
| 8905 | if (l == VT_JMP) | 8905 | if (l == VT_JMP) |
| 8906 | return has_init ? v : 1; | 8906 | return has_init ? v : 1; |
| 8907 | if (l == VT_CMP) | 8907 | skip(';'); |
| 8908 | skip(';'); | ||
| 8909 | else if (tok == ';') | ||
| 8910 | next(); | ||
| 8911 | break; | 8908 | break; |
| 8912 | } | 8909 | } |
| 8913 | next(); | 8910 | next(); |
| @@ -179,7 +179,7 @@ bar : 3 ; 3 · 178 unmodified lines | |||
| 179 | 60_errors_and_warnings.c:372: error: statement expression outside of function | 179 | 60_errors_and_warnings.c:372: error: statement expression outside of function |
| 180 | 180 | ||
| 181 | [test_invalid_tokckill] | 181 | [test_invalid_tokckill] |
| 182 | 60_errors_and_warnings.c:375: warning: function might return no value: 'f' | 182 | 60_errors_and_warnings.c:375: error: ';' expected (got '3') |
| 183 | 183 | ||
| 184 | [test_duplicate_member] | 184 | [test_duplicate_member] |
| 185 | 60_errors_and_warnings.c:381: error: duplicate member 'a' | 185 | 60_errors_and_warnings.c:381: error: duplicate member 'a' |