├── .gitignore ├── CHANGES.txt ├── LICENSE ├── Makefile ├── NOTICE ├── carburetta.sln ├── examples ├── calc │ └── calc.cbrt ├── inireader │ ├── ini_reader.h │ ├── iniparser.cbrt │ └── main.c ├── kc │ ├── 3rdparty │ │ └── dtoa_david_m_gay │ │ │ ├── README.txt │ │ │ └── dtoa.c │ ├── README.md │ ├── helpers │ │ ├── aes.c │ │ ├── aes.h │ │ ├── cpp_helpers.cpp │ │ ├── gen_unicode_data.sln │ │ ├── gen_unicode_data │ │ │ ├── UnicodeData.txt │ │ │ ├── gen_unicode_data.c │ │ │ ├── gen_unicode_data.vcxproj │ │ │ └── gen_unicode_data.vcxproj.filters │ │ ├── gf8.c │ │ ├── gf8.h │ │ ├── helpers.c │ │ ├── helpers.h │ │ ├── klt_logger.c │ │ ├── klt_logger.h │ │ ├── md5.c │ │ ├── md5.h │ │ ├── sha1.c │ │ ├── sha1.h │ │ ├── sha256.c │ │ ├── sha256.h │ │ ├── unicode_data.c │ │ └── unicode_data.h │ └── src │ │ ├── c_compiler.c │ │ ├── c_compiler.h │ │ ├── c_parser.cbrt │ │ ├── data_section.c │ │ ├── data_section.h │ │ ├── decl.c │ │ ├── decl.h │ │ ├── dynamic_runtime_linking.c │ │ ├── dynamic_runtime_linking.h │ │ ├── expr.c │ │ ├── expr.h │ │ ├── expr_node_types.h │ │ ├── func_def.c │ │ ├── func_def.h │ │ ├── input_file.c │ │ ├── input_file.h │ │ ├── invoke_call_x64.asm │ │ ├── invoke_x64.c │ │ ├── invoke_x64.h │ │ ├── jitmem.c │ │ ├── jitmem.h │ │ ├── name_space.c │ │ ├── name_space.h │ │ ├── nix_invoke_call_x64.s │ │ ├── nix_invoke_x64.c │ │ ├── partial_type_specifiers.c │ │ ├── partial_type_specifiers.h │ │ ├── pp_const_expr.cbrt │ │ ├── pp_line_continuations.cbrt │ │ ├── pp_line_directives.cbrt │ │ ├── pp_macro_expander.cbrt │ │ ├── pp_tokenizer.cbrt │ │ ├── pp_tokens.c │ │ ├── pp_tokens.h │ │ ├── pp_trigraphs.cbrt │ │ ├── pplinedirectives.cbrt │ │ ├── scan_helpers.c │ │ ├── scan_helpers.h │ │ ├── situs.c │ │ ├── situs.h │ │ ├── stmt.c │ │ ├── stmt.h │ │ ├── switch.c │ │ ├── switch.h │ │ ├── symtab.c │ │ ├── symtab.h │ │ ├── templ_parser.c │ │ ├── templ_parser.h │ │ ├── types.c │ │ └── types.h ├── template_scan │ └── template_scan.cbrt └── tilly │ ├── directive_input_splitter.cbrt │ ├── directive_input_splitter_defs.h │ ├── directives.cbrt │ ├── directives_defs.h │ ├── line_continuation.cbrt │ ├── line_continuation_defs.h │ ├── multi_line_comments.cbrt │ ├── multi_line_comments_defs.h │ ├── situs.cpp │ ├── situs.h │ ├── snippets.cbrt │ ├── tiles.cbrt │ ├── tiles_defs.h │ ├── tilly.cpp │ ├── tilly_parser.cpp │ └── tilly_parser.h ├── project ├── calc.vcxproj ├── calc.vcxproj.filters ├── calc.vcxproj.user ├── carburetta.vcxproj ├── carburetta.vcxproj.filters ├── inireader │ ├── inireader.vcxproj │ ├── inireader.vcxproj.filters │ └── inireader.vcxproj.user ├── kc.vcxproj ├── kc.vcxproj.filters ├── kc.vcxproj.user ├── template_scan.vcxproj ├── template_scan.vcxproj.filters ├── template_scan.vcxproj.user ├── tester.vcxproj ├── tester.vcxproj.filters ├── tester.vcxproj.user ├── tilly.vcxproj └── tilly.vcxproj.filters ├── readme.md ├── src ├── carburetta.c ├── carburetta_context.c ├── carburetta_context.h ├── chain.c ├── chain.h ├── decomment.c ├── decomment.h ├── dfa.c ├── dfa.h ├── emit_c.c ├── emit_c.h ├── grammar_table.c ├── grammar_table.h ├── indented_printer.c ├── indented_printer.h ├── lalr.c ├── lalr.h ├── line_assembly.c ├── line_assembly.h ├── line_defs.c ├── line_defs.h ├── mode.c ├── mode.h ├── mul.c ├── mul.h ├── nfa.c ├── nfa.h ├── parse_input.c ├── parse_input.h ├── prd_gram.c ├── prd_gram.h ├── prd_grammar.c ├── prd_grammar.cbrt ├── prd_grammar.h ├── regex_grammar.c ├── regex_grammar.cbrt ├── regex_grammar.h ├── report_error.c ├── report_error.h ├── rex.c ├── rex.h ├── rex_parse.c ├── rex_parse.cbrt ├── rex_parse.h ├── rex_set_range.c ├── rex_set_range.h ├── scanner.c ├── scanner.h ├── snippet.c ├── snippet.h ├── symbol.c ├── symbol.h ├── temp_output.c ├── temp_output.h ├── tokenizer.c ├── tokenizer.h ├── tokens.c ├── tokens.h ├── tokens_generated_scanners.c ├── typestr.c ├── typestr.h ├── uc_cat_ranges.c ├── uc_cat_ranges.h ├── version.h ├── xlalr.c ├── xlalr.h ├── xlts.c └── xlts.h └── tester ├── cpp ├── t10.cbrt ├── t11.cbrt ├── t12.cbrt ├── t13.cbrt ├── t14.cbrt ├── t15.cbrt ├── t16.cbrt ├── t17.cbrt ├── t18.cbrt ├── t19.cbrt ├── t8.cbrt └── t9.cbrt ├── t1.cbrt ├── t2.cbrt ├── t3.cbrt ├── t4.cbrt ├── t5.cbrt ├── t6.cbrt ├── t7.cbrt └── tester.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Visual studio 55 | .vs/ 56 | build/ 57 | cinder.vcxproj.user 58 | /project/carburetta.vcxproj.user 59 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC ?= gcc 2 | CFLAGS ?= -Wall 3 | CXXFLAGS ?= -Wall 4 | CXXLDFLAGS ?= -lstdc++ 5 | LDFLAGS ?= 6 | DESTDIR ?= /usr/local 7 | PREFIX ?= 8 | 9 | OUT = build 10 | SRC = src 11 | INTERMEDIATE = build/objs 12 | 13 | SOURCES = $(filter-out src/tokens_generated_scanners.c,$(wildcard $(SRC)/*.c)) 14 | OBJECTS = $(patsubst $(SRC)/%.c,$(INTERMEDIATE)/%.o,$(SOURCES)) 15 | TESTS_SRC = $(wildcard tester/*.cbrt) 16 | TESTS_CPP_SRC = $(wildcard tester/cpp/*.cbrt) 17 | TESTS_C = $(patsubst tester/%.cbrt,$(INTERMEDIATE)/tester/%.c,$(TESTS_SRC)) 18 | TESTS_CPP = $(patsubst tester/cpp/%.cbrt,$(INTERMEDIATE)/tester/cpp/%.cpp,$(TESTS_CPP_SRC)) 19 | TESTS_CPP_OBJ = $(patsubst tester/cpp/%.cbrt,$(INTERMEDIATE)/tester/cpp/%.o,$(TESTS_CPP_SRC)) 20 | 21 | TILLY_CBRT_SRC = $(wildcard examples/tilly/*.cbrt) 22 | TILLY_CPP_SRC = $(wildcard examples/tilly/*.cpp) 23 | TILLY_CBRT_CPP_SRC = $(patsubst examples/tilly/%.cbrt,$(INTERMEDIATE)/tilly/%.cpp,$(TILLY_CBRT_SRC)) 24 | TILLY_CBRT_CPP_OBJ = $(patsubst examples/tilly/%.cbrt,$(INTERMEDIATE)/tilly/%.o,$(TILLY_CBRT_SRC)) 25 | TILLY_CPP_OBJ = $(patsubst examples/tilly/%.cpp,$(INTERMEDIATE)/tilly/%.o,$(TILLY_CPP_SRC)) 26 | 27 | .PHONY: all 28 | all: $(OUT)/carburetta $(OUT)/calc $(OUT)/template_scan $(OUT)/inireader $(OUT)/tilly $(OUT)/tester 29 | 30 | $(INTERMEDIATE)/%.o: $(SRC)/%.c 31 | @mkdir -p $(@D) 32 | $(CC) $(CFLAGS) -c -o $@ $< 33 | 34 | $(OUT)/carburetta: $(OBJECTS) 35 | $(CC) -o $(OUT)/carburetta $(OBJECTS) $(LDFLAGS) 36 | 37 | $(INTERMEDIATE)/calc/calc.c: $(OUT)/carburetta examples/calc/calc.cbrt 38 | mkdir -p $(@D) 39 | $(OUT)/carburetta examples/calc/calc.cbrt --c $(INTERMEDIATE)/calc/calc.c 40 | 41 | $(INTERMEDIATE)/inireader/iniparser.c: $(OUT)/carburetta examples/inireader/iniparser.cbrt 42 | mkdir -p $(@D) 43 | $(OUT)/carburetta examples/inireader/iniparser.cbrt --c $(INTERMEDIATE)/inireader/iniparser.c --h 44 | 45 | $(INTERMEDIATE)/template_scan/template_scan.c: $(OUT)/carburetta examples/template_scan/template_scan.cbrt 46 | mkdir -p $(@D) 47 | $(OUT)/carburetta examples/template_scan/template_scan.cbrt --c $(INTERMEDIATE)/template_scan/template_scan.c 48 | 49 | $(OUT)/calc: $(INTERMEDIATE)/calc/calc.c 50 | $(CC) $(CFLAGS) -o $(OUT)/calc $(INTERMEDIATE)/calc/calc.c $(LDFLAGS) 51 | 52 | $(OUT)/inireader: $(INTERMEDIATE)/inireader/iniparser.c examples/inireader/main.c 53 | $(CC) $(CFLAGS) -o $(OUT)/inireader -I$(INTERMEDIATE)/inireader -Iexamples/inireader $(INTERMEDIATE)/inireader/iniparser.c examples/inireader/main.c $(LDFLAGS) 54 | 55 | $(OUT)/template_scan: $(INTERMEDIATE)/template_scan/template_scan.c 56 | $(CC) $(CFLAGS) -o $(OUT)/template_scan $(INTERMEDIATE)/template_scan/template_scan.c $(LDFLAGS) 57 | 58 | .PRECIOUS: $(INTERMEDIATE)/tester/%.c 59 | $(INTERMEDIATE)/tester/%.c: tester/%.cbrt 60 | mkdir -p $(@D) 61 | $(OUT)/carburetta $< --c $@ --h 62 | 63 | $(INTERMEDIATE)/tester/t3.c: tester/t3.cbrt 64 | mkdir -p $(@D) 65 | $(OUT)/carburetta --x-raw $< --c $@ --h 66 | 67 | .PRECIOUS: $(INTERMEDIATE)/tester/cpp/%.cpp 68 | $(INTERMEDIATE)/tester/cpp/%.cpp: tester/cpp/%.cbrt 69 | mkdir -p $(@D) 70 | $(OUT)/carburetta $< --c $@ --h 71 | 72 | $(INTERMEDIATE)/tester/cpp/%.o: $(INTERMEDIATE)/tester/cpp/%.cpp 73 | $(CC) $(CXXFLAGS) -c $^ -o $@ 74 | 75 | $(OUT)/tester: $(TESTS_C) $(TESTS_CPP_OBJ) tester/tester.c 76 | $(CC) $(CFLAGS) -o $@ $^ $(CXXLDFLAGS) 77 | 78 | 79 | .PRECIOUS: $(INTERMEDIATE)/tilly/%.cpp 80 | $(INTERMEDIATE)/tilly/%.cpp: examples/tilly/%.cbrt 81 | mkdir -p $(@D) 82 | $(OUT)/carburetta $< --c $@ --h 83 | 84 | $(INTERMEDIATE)/tilly/%.o: $(INTERMEDIATE)/tilly/%.cpp $(TILLY_CBRT_CPP_SRC) 85 | $(CC) $(CXXFLAGS) -c $< -o $@ -I examples/tilly/ -I $(INTERMEDIATE)/tilly/ 86 | 87 | $(INTERMEDIATE)/tilly/%.o: examples/tilly/%.cpp $(TILLY_CBRT_CPP_SRC) 88 | $(CC) $(CXXFLAGS) -c $< -o $@ -I examples/tilly/ -I $(INTERMEDIATE)/tilly/ 89 | 90 | $(OUT)/tilly: $(TILLY_CPP_OBJ) $(TILLY_CBRT_CPP_OBJ) 91 | $(CC) -o $@ $^ $(CXXLDFLAGS) 92 | 93 | .PHONY: clean 94 | clean: 95 | @rm -rf $(OUT) 96 | 97 | .PHONY: install 98 | install: all 99 | install $(OUT)/carburetta $(DESTDIR)$(PREFIX)/bin 100 | 101 | .PHONY: uninstall 102 | uninstall: 103 | rm $(DESTDIR)$(PREFIX)/bin/carburetta 104 | 105 | .PHONY: test 106 | test: all 107 | $(OUT)/tester 108 | 109 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | ========================================================================= 2 | == NOTICE file corresponding to the section 4 d of == 3 | == the Apache License, Version 2.0 == 4 | ========================================================================= 5 | 6 | Carburetta Parser Generator 7 | Copyright 2020-2021 Kinglet B.V. 8 | 9 | This product includes software developed by Kinglet B.V. at 10 | https://carburetta.com/ 11 | -------------------------------------------------------------------------------- /examples/calc/calc.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | %scanner% 20 | %prefix calc_ 21 | 22 | INTEGER: [0-9]+ { $$ = atoi($text); fprintf(stderr, "%s\n", $text); } 23 | 24 | : [\ \n]+; /* skip spaces and newlines */ 25 | PLUS: \+; 26 | MINUS: \-; 27 | ASTERISK: \*; 28 | SLASH: /; 29 | PAR_OPEN: \(; 30 | PAR_CLOSE: \); 31 | 32 | %token PLUS MINUS ASTERISK SLASH PAR_OPEN PAR_CLOSE INTEGER 33 | %nt grammar expr term factor value 34 | 35 | %grammar% 36 | 37 | %type grammar expr term factor value INTEGER: int 38 | %constructor $$ = 0; 39 | %destructor /* destructing */ $$ = 0; 40 | 41 | %common_type int 42 | %destructor /* destructing common */ $$ = 0; 43 | 44 | %params int *final_result 45 | 46 | grammar: expr { 47 | printf("Outcome: %d\n", $0); 48 | *final_result = $0; 49 | } 50 | 51 | expr: term { $$ = $0; } 52 | expr: expr PLUS term { $$ = $0 + $2; } 53 | expr: expr MINUS term { $$ = $0 - $2; } 54 | 55 | term: factor { $$ = $0; } 56 | term: term ASTERISK factor { $$ = $0 * $2; } 57 | term: term SLASH factor { $$ = $0 / $2; } 58 | 59 | factor: value { $$ = $0; } 60 | factor: MINUS factor { $$ = -$1; } 61 | factor: PAR_OPEN expr PAR_CLOSE { $$ = $1; } 62 | 63 | value: INTEGER { $$ = $0; } 64 | 65 | %% 66 | void report_error(const char *msg) { 67 | fprintf(stderr, "%s", msg); 68 | } 69 | %% 70 | 71 | value: error { $$ = 0; report_error("Syntax error: value expected;\n"); } 72 | 73 | %% 74 | 75 | int main(int argc, char **argv) { 76 | int value, r; 77 | static char s[300]; 78 | 79 | fprintf(stderr, "Enter an expression (-1 to exit):\n"); 80 | 81 | 82 | struct calc_stack stack; 83 | calc_stack_init(&stack); 84 | 85 | do { 86 | if (!fgets(s, sizeof(s), stdin)) { 87 | perror("Error reading"); 88 | r = EXIT_FAILURE; 89 | break; 90 | } 91 | if (strlen(s) && (s[strlen(s) - 1] == '\n')) { 92 | /* Remove \n so we can check end of input */ 93 | calc_set_input(&stack, s, strlen(s) - 1, 1); 94 | } 95 | else { 96 | calc_set_input(&stack, s, strlen(s), 1); 97 | } 98 | do { 99 | r = calc_scan(&stack, &value); 100 | if (r == _CALC_SYNTAX_ERROR) { 101 | fprintf(stderr, "Syntax error\n"); 102 | } 103 | } while (r == _CALC_SYNTAX_ERROR); 104 | 105 | if (r) { 106 | if (r == _CALC_LEXICAL_ERROR) { 107 | fprintf(stderr, "Lexical error\n"); 108 | } 109 | else { 110 | fprintf(stderr, "Unexpected error\n"); 111 | } 112 | r = EXIT_FAILURE; 113 | break; 114 | } 115 | } while (value != -1); 116 | calc_stack_cleanup(&stack); 117 | 118 | return r; 119 | } 120 | -------------------------------------------------------------------------------- /examples/inireader/ini_reader.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef INI_READER_H 17 | #define INI_READER_H 18 | 19 | #ifndef INIPARSER_H_INCLUDED 20 | #define INIPARSER_H_INCLUDED 21 | /* Generated by Carburetta from iniparser.cbrt. 22 | * Extra care must be taken that this generated file is on the include path of the compiler. 23 | * A forward declaration for struct ini_reader is needed for the prototype of scan() and parse() */ 24 | struct ini_reader; 25 | #include "iniparser.h" 26 | #endif 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /* Return values to indicate what is happening. These return values share the same "space" as 33 | * the Carburetta generated _INIPARSER_FINISH, _INIPARSER_MATCH and so on, return codes. Those 34 | * generates codes start from 0 onwards, these codes are negative, ensuring they won't conflict. */ 35 | #define INI_READER_SECTION -1 36 | #define INI_READER_KEY_VALUE -2 37 | #define INI_READER_IO_ERROR -3 38 | 39 | struct ini_reader { 40 | struct iniparser_stack stack_; 41 | 42 | /* Section string 43 | * Valid when INI_READER_SECTION if returned. */ 44 | char *section_; 45 | 46 | /* Key string; valid when INI_READER_KEY_VALUE is returned. */ 47 | const char *key_; 48 | 49 | /* Value string; this is the string from the '=' symbol up to the end of the line, 50 | * but not including the newline. */ 51 | const char *value_; 52 | }; 53 | 54 | void ini_reader_init(struct ini_reader *ir); 55 | void ini_reader_cleanup(struct ini_reader *ir); 56 | int ini_reader_read(struct ini_reader *ir, FILE *fp); 57 | 58 | #ifdef __cplusplus 59 | } /* extern "C" */ 60 | #endif 61 | 62 | #endif /* INI_READ_H */ 63 | -------------------------------------------------------------------------------- /examples/inireader/main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | #include "ini_reader.h" 20 | 21 | int main(int argc, char **argv) { 22 | FILE *inputfp = stdin; 23 | const char *inputfile = NULL; 24 | 25 | /* Find input file amongst the arguments. */ 26 | int n; 27 | for (n = 1; n < argc; ++n) { 28 | if ((argv[n][0] == '-') && (argv[n][1] == '-')) { 29 | /* Skip value for the argument */ 30 | if ((n + 1) < argc) n++; 31 | continue; 32 | } 33 | /* Not an -- style argument, use it as input file */ 34 | inputfile = argv[n]; 35 | inputfp = fopen(argv[n], "rb"); 36 | if (!inputfp) { 37 | fprintf(stderr, "Failed to open input file \"%s\"\n", argv[n]); 38 | return EXIT_FAILURE; 39 | } 40 | } 41 | 42 | struct ini_reader ir; 43 | ini_reader_init(&ir); 44 | 45 | int done = 0; 46 | int failed = 0; 47 | while (!done) { 48 | switch (ini_reader_read(&ir, inputfp)) { 49 | /* Handle the error conditions first... */ 50 | case _INIPARSER_LEXICAL_ERROR: 51 | fprintf(stderr, "Line %d, column %d: Lexical error\n", iniparser_line(&ir.stack_), iniparser_column(&ir.stack_)); 52 | done = 1; 53 | failed = 1; 54 | break; 55 | case _INIPARSER_INTERNAL_ERROR: 56 | fprintf(stderr, "Line %d, column %d: Internal error\n", iniparser_line(&ir.stack_), iniparser_column(&ir.stack_)); 57 | done = 1; 58 | failed = 1; 59 | break; 60 | case _INIPARSER_NO_MEMORY: 61 | /* No memory, malloc() returned NULL. May retry if there is some way to free up memory first; here there is not. */ 62 | fprintf(stderr, "Line %d, column %d: No memory\n", iniparser_line(&ir.stack_), iniparser_column(&ir.stack_)); 63 | done = 1; 64 | failed = 1; 65 | break; 66 | case _INIPARSER_OVERFLOW: 67 | /* Overflow, very unlikely to occur but when it does it typically suggests corruption like stray pointers and the like. */ 68 | fprintf(stderr, "Line %d, column %d: Overflow\n", iniparser_line(&ir.stack_), iniparser_column(&ir.stack_)); 69 | done = 1; 70 | failed = 1; 71 | break; 72 | case INI_READER_IO_ERROR: 73 | /* We defined this errorcode ourselves, it is not generated by Carburetta (as Carburetta generated code will not do the 74 | * actual IO itself.) */ 75 | fprintf(stderr, "I/O error trying to read from %s", inputfile ? inputfile : "stdin"); 76 | done = 1; 77 | failed = 1; 78 | break; 79 | 80 | /* Now for the business as usual conditions. */ 81 | 82 | /* Success conditions */ 83 | case INI_READER_SECTION: 84 | fprintf(stdout, "Section: \"%s\" found\n", ir.section_); 85 | break; 86 | case INI_READER_KEY_VALUE: 87 | fprintf(stdout, "Key: \"%s\" Value: \"%s\"\n", ir.key_, ir.value_); 88 | break; 89 | 90 | case _INIPARSER_FINISH: 91 | /* Good result */ 92 | done = 1; 93 | failed = 0; 94 | break; 95 | } 96 | } 97 | 98 | ini_reader_cleanup(&ir); 99 | 100 | fclose(inputfp); 101 | 102 | return failed ? EXIT_FAILURE : EXIT_SUCCESS; 103 | 104 | } 105 | -------------------------------------------------------------------------------- /examples/kc/3rdparty/dtoa_david_m_gay/README.txt: -------------------------------------------------------------------------------- 1 | The original "dtoa.c" has been changed: 2 | - The strtod() function has been renamed to strtod_david_m_gay(). 3 | This avoids a conflict with the C library version. 4 | -------------------------------------------------------------------------------- /examples/kc/README.md: -------------------------------------------------------------------------------- 1 | # "kc", C99 interpreter/compiler front-end example (WIP) 2 | 3 | This is an example that shows how to implement a C compiler (C99 standard 4 | to be specific) using Carburetta, through all of its 7 translation phases. 5 | 6 | It currently does not have a backend (although the "Tilly example" elsewhere 7 | might be useful for this); and instead can execute the compiled code through 8 | interpretation. 9 | 10 | Because of function pointers being what they are, there is some JIT 11 | trampoline code in invoke_x64.c/h and invoke_call_x64.asm that ties this, 12 | otherwise portable, code to the Windows x64 ABI and MASM. Consequently, the 13 | example will not work on non-Windows platforms. (The nix_invoke_XXX is not 14 | where it needs to be.) 15 | 16 | Finally, there is a C preprocessor here that the preprocessor from Aex-GL was 17 | based on (see https://github.com/kingletbv/aex-gl src/pp in particular.) The 18 | one in Aex-GL is seperated out into its own module, it would be nice to re- 19 | integrate it, or at least backport the fixes there into here. Note however 20 | that OpenGL ES 2.0 has extensions to a standard preprocessor, so it is not 21 | trivial to blank these out conditionally (or desirable to have those 22 | extensions here as dormant code.) 23 | -------------------------------------------------------------------------------- /examples/kc/helpers/aes.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef KLT_AES_H 17 | #define KLT_AES_H 18 | 19 | #ifndef INCLUDED_STDINT_H 20 | #define INCLUDED_STDINT_H 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* If KLT_AES_INVISIBLE_LINKAGE is defined, including "aes.h" will not only 29 | * declare but also define (as static) the implementation */ 30 | #ifdef KLT_AES_INVISIBLE_LINKAGE 31 | #define KLT_AES_OPTIONAL_STATIC static 32 | #else 33 | #define KLT_AES_OPTIONAL_STATIC 34 | #endif 35 | 36 | KLT_AES_OPTIONAL_STATIC void aes128_keyexpansion(uint8_t *key/*[16]*/, uint8_t *w/*[176]*/); 37 | KLT_AES_OPTIONAL_STATIC void aes128_cipher(uint8_t *in/*[16]*/, uint8_t *out/*[16]*/, uint8_t *w/*[176]*/); 38 | KLT_AES_OPTIONAL_STATIC void aes128_inv_cipher(uint8_t *in/*[16]*/, uint8_t *out/*[16]*/, uint8_t *w/*[176]*/); 39 | 40 | KLT_AES_OPTIONAL_STATIC void aes192_keyexpansion(uint8_t *key/*[24]*/, uint8_t *w/*[208]*/); 41 | KLT_AES_OPTIONAL_STATIC void aes192_cipher(uint8_t *in/*[16]*/, uint8_t *out/*[16]*/, uint8_t *w/*[208]*/); 42 | KLT_AES_OPTIONAL_STATIC void aes192_inv_cipher(uint8_t *in/*[16]*/, uint8_t *out/*[16]*/, uint8_t *w/*[208]*/); 43 | 44 | KLT_AES_OPTIONAL_STATIC void aes256_keyexpansion(uint8_t *key/*[32]*/, uint8_t *w/*[240]*/); 45 | KLT_AES_OPTIONAL_STATIC void aes256_cipher(uint8_t *in/*[16]*/, uint8_t *out/*[16]*/, uint8_t *w/*[240]*/); 46 | KLT_AES_OPTIONAL_STATIC void aes256_inv_cipher(uint8_t *in/*[16]*/, uint8_t *out/*[16]*/, uint8_t *w/*[240]*/); 47 | 48 | KLT_AES_OPTIONAL_STATIC void aes_gen_sbox(void); 49 | KLT_AES_OPTIONAL_STATIC void aes_gen_c(void); 50 | 51 | #ifdef KLT_AES_INVISIBLE_LINKAGE 52 | #include "aes.c" 53 | #endif 54 | 55 | #ifdef __cplusplus 56 | } /* extern "C" */ 57 | #endif 58 | 59 | #endif /* KLT_AES_H */ 60 | -------------------------------------------------------------------------------- /examples/kc/helpers/cpp_helpers.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | 17 | #ifndef _MSC_VER 18 | /* We need the declaration for vasprintf() which is a GNU extension, 19 | * this instructs clang to include the declaration. */ 20 | #ifndef _GNU_SOURCE 21 | #define _GNU_SOURCE 22 | #endif 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef _WIN32 33 | #include 34 | 35 | #define WIN32_LEAN_AND_MEAN 36 | #include 37 | #endif 38 | 39 | #include "helpers.h" 40 | 41 | #ifdef _MSC_VER 42 | std::string mstrprintf(const char *format, ...) { 43 | std::string s; 44 | va_list args; 45 | va_start(args, format); 46 | int len = _vscprintf(format, args); 47 | s.resize(len + 1); /* +1 to accommodate null terminator */ 48 | vsprintf(&s[0], format, args); 49 | s.resize(len); /* -1 to remove null terminator from the string (std::string will have its own null terminator. */ 50 | va_end(args); 51 | return s; 52 | } 53 | #else 54 | std::string mstrprintf(const char *format, ...) { 55 | va_list args; 56 | va_start(args, format); 57 | char *p; 58 | int len = vasprintf(&p, format, args); 59 | va_end(args); 60 | if (len == -1) { 61 | return std::string(""); 62 | } 63 | std::string s(p, len); 64 | free(p); 65 | return s; 66 | } 67 | #endif 68 | 69 | #ifdef _TCHAR_DEFINED 70 | std::string tstr2str(const TCHAR *tsrc) { 71 | char *s = tstr2acstr(tsrc); 72 | std::string str(s); 73 | free(s); 74 | return str; 75 | } 76 | 77 | TCHAR *str2tstr(const std::string &str) { 78 | return cstr2atstr(str.c_str()); 79 | } 80 | 81 | freeing_tstr str2ftstr(const std::string &ftstr) { 82 | freeing_tstr f; 83 | f.s = str2tstr(ftstr); 84 | return f; /* Rely on move ellision to not call destructor here.. */ 85 | } 86 | #endif /* _TCHAR_DEFINED */ 87 | -------------------------------------------------------------------------------- /examples/kc/helpers/gen_unicode_data.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.6 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gen_unicode_data", "gen_unicode_data\gen_unicode_data.vcxproj", "{F8395D20-098A-411A-B5FF-675B75D62B31}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {F8395D20-098A-411A-B5FF-675B75D62B31}.Debug|x64.ActiveCfg = Debug|x64 17 | {F8395D20-098A-411A-B5FF-675B75D62B31}.Debug|x64.Build.0 = Debug|x64 18 | {F8395D20-098A-411A-B5FF-675B75D62B31}.Debug|x86.ActiveCfg = Debug|Win32 19 | {F8395D20-098A-411A-B5FF-675B75D62B31}.Debug|x86.Build.0 = Debug|Win32 20 | {F8395D20-098A-411A-B5FF-675B75D62B31}.Release|x64.ActiveCfg = Release|x64 21 | {F8395D20-098A-411A-B5FF-675B75D62B31}.Release|x64.Build.0 = Release|x64 22 | {F8395D20-098A-411A-B5FF-675B75D62B31}.Release|x86.ActiveCfg = Release|Win32 23 | {F8395D20-098A-411A-B5FF-675B75D62B31}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /examples/kc/helpers/gen_unicode_data/gen_unicode_data.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/kc/helpers/gf8.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef KLT_GF8_H 17 | #define KLT_GF8_H 18 | 19 | #ifndef INCLUDED_STDINT_H 20 | #define INCLUDED_STDINT_H 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* If KLT_GF8_INVISIBLE_LINKAGE is defined, including "sha1.h" will not only 29 | * declare but also define (as static) the implementation */ 30 | #ifdef KLT_GF8_INVISIBLE_LINKAGE 31 | #define KLT_GF8_OPTIONAL_STATIC static 32 | #else 33 | #define KLT_GF8_OPTIONAL_STATIC 34 | #endif 35 | 36 | KLT_GF8_OPTIONAL_STATIC uint8_t gf8_xtime(uint8_t val, uint8_t irreducible); 37 | 38 | KLT_GF8_OPTIONAL_STATIC uint8_t gf8_mul(uint8_t lvalue, uint8_t rvalue, uint8_t irreducible); 39 | KLT_GF8_OPTIONAL_STATIC void gf8_init_tables(uint8_t irreducible); 40 | KLT_GF8_OPTIONAL_STATIC uint8_t gf8_tbl_inverse(uint8_t x); 41 | KLT_GF8_OPTIONAL_STATIC uint8_t gf8_tbl_divide(uint8_t lvalue, uint8_t rvalue); 42 | KLT_GF8_OPTIONAL_STATIC uint8_t gf8_tbl_multiply(uint8_t lvalue, uint8_t rvalue); 43 | 44 | KLT_GF8_OPTIONAL_STATIC void gf8_gen_c(void); 45 | 46 | #ifdef KLT_GF8_INVISIBLE_LINKAGE 47 | #include "gf8.c" 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } /* extern "C" */ 52 | #endif 53 | 54 | #endif /* KLT_GF8_H */ 55 | -------------------------------------------------------------------------------- /examples/kc/helpers/klt_logger.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef KLT_LOGGER2_H 17 | #define KLT_LOGGER2_H 18 | 19 | #ifndef STDARG_H_INCLUDED 20 | #define STDARG_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | #define KLT_LOG_NODE_FLAG_DEFINITIONS_MASK 3 29 | #define KLT_LOG_NODE_FLAG_FUNCTION_DEFINITION 1 30 | #define KLT_LOG_NODE_FLAG_ENABLED_DEFINITION 2 31 | 32 | #define KLT_LOG_NODE_FLAG_ENABLED 128 33 | 34 | #define KLT_LOG_ERROR_LEVEL 1 35 | #define KLT_LOG_LOG_LEVEL 2 36 | #define KLT_LOG_TRACE_LEVEL 3 37 | 38 | struct klt_log_node; 39 | 40 | typedef void (*klt_log_fn)(struct klt_log_node *ln, void *baton, int level, const char *file, int line, const char *fmt, va_list args); 41 | 42 | struct klt_log_anchor { 43 | /* Compile-time, statically allocated name of the module as a full path. */ 44 | const char *full_path_initializer_; 45 | 46 | /* Node at which this anchor exists (logging for the anchor occurs on this node) */ 47 | struct klt_log_node *node_; 48 | struct klt_log_anchor *next_in_node_, *prev_in_node_; 49 | }; 50 | 51 | struct klt_log_node { 52 | /* Node name of the module */ 53 | char *name_; 54 | 55 | /* Navigation through the logger hierarchy.. */ 56 | struct klt_log_node *parent_; 57 | struct klt_log_node *first_child_; 58 | struct klt_log_node *next_sibling_, *prev_sibling_; 59 | 60 | /* Flags field, the flags_carried_ field is used at runtime to 61 | * propagate attributes down the hierarchy. */ 62 | int flags_, flags_carried_; 63 | 64 | /* Pointer to the log function used by this log node if it is enabled. 65 | * If this pointer is NULL, the log function is inherited from its parent. */ 66 | klt_log_fn log_fn_ptr_; 67 | void *log_fn_baton_; 68 | 69 | /* Chain of anchors at this node, each of which may be either a source for logging or a destination 70 | * for logging. */ 71 | struct klt_log_anchor *first_anchor_; 72 | }; 73 | 74 | extern void *g_log_global_lock_; 75 | extern struct klt_log_node *g_log_root_; 76 | extern struct klt_log_anchor g_log_root_anchor_; 77 | 78 | #ifndef KLT_LOG_MODULE 79 | #define KLT_LOGGER_TO_USE g_log_root_anchor_ 80 | #else 81 | #define KLT_LOGGER_TO_USE g_log_module_anchor 82 | static struct klt_log_anchor g_log_module_anchor = { 83 | KLT_LOG_MODULE, 84 | NULL, NULL, NULL 85 | }; 86 | #endif 87 | 88 | #define LOGERROR(...) \ 89 | klt_log(&KLT_LOGGER_TO_USE, KLT_LOG_ERROR_LEVEL, __FILE__, __LINE__, __VA_ARGS__); 90 | 91 | #define LOG(...) \ 92 | klt_log(&KLT_LOGGER_TO_USE, KLT_LOG_LOG_LEVEL, __FILE__, __LINE__, __VA_ARGS__); 93 | 94 | #define TRACE(...) \ 95 | klt_log(&KLT_LOGGER_TO_USE, KLT_LOG_TRACE_LEVEL, __FILE__, __LINE__, __VA_ARGS__); 96 | 97 | 98 | void klt_logger_init(void); 99 | void klt_logger_cleanup(void); 100 | 101 | void klt_log_node_init(struct klt_log_node *node); 102 | void klt_log_node_cleanup(struct klt_log_node *node); 103 | 104 | void klt_log_set_function(const char *module, klt_log_fn fn, void *fn_baton); 105 | void klt_log_clear_function(const char *module); 106 | 107 | void klt_log_set_module_enable(const char *module, int enable); 108 | void klt_log_clear_module_enable(const char *module); 109 | 110 | klt_log_fn klt_log_set_current_thread_intercept(klt_log_fn fn, void *baton, void **original_baton); 111 | klt_log_fn klt_log_clear_current_thread_intercept(void **original_baton); 112 | 113 | void klt_log(struct klt_log_anchor *origin_anchor, int level, const char *file, int line, const char *fmt, ...); 114 | 115 | #ifdef __cplusplus 116 | } /* extern "C" */ 117 | #endif 118 | 119 | #endif /* KLT_LOGGER2_H */ 120 | -------------------------------------------------------------------------------- /examples/kc/helpers/md5.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef KLT_MD5_H 17 | #define KLT_MD5_H 18 | 19 | #ifndef INCLUDED_STDINT_H 20 | #define INCLUDED_STDINT_H 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | struct md5_inner_state { 29 | uint32_t a_, b_, c_, d_; 30 | uint32_t chunk_[16]; 31 | uint64_t message_bit_length_; 32 | int current_byte_index_; 33 | uint32_t current_word_; 34 | }; 35 | 36 | /* If KLT_MD5_INVISIBLE_LINKAGE is defined, including "md5.h" will not only 37 | * declare but also define (as static) the implementation */ 38 | #ifdef KLT_MD5_INVISIBLE_LINKAGE 39 | #define KLT_MD5_OPTIONAL_STATIC static 40 | #else 41 | #define KLT_MD5_OPTIONAL_STATIC 42 | #endif 43 | 44 | /* Initializes the state for computing a MD5 value */ 45 | KLT_MD5_OPTIONAL_STATIC void md5_init(struct md5_inner_state *state); 46 | 47 | /* Processes message data for the MD5 being computed in state. This function 48 | * can be called multiple times in succession for consecutive parts of the same 49 | * message. 50 | * Returns 0 upon success, or -1 upon failure. */ 51 | KLT_MD5_OPTIONAL_STATIC int md5_process(struct md5_inner_state *state, const void *message_part, size_t message_part_size); 52 | 53 | /* Completes computation of the MD5 hash and writes it to the 16 bytes at 54 | * digest. Returns 0 upon success, or -1 upon failure. */ 55 | KLT_MD5_OPTIONAL_STATIC int md5_finish(struct md5_inner_state *state, uint8_t *digest); 56 | 57 | #ifdef KLT_MD5_INVISIBLE_LINKAGE 58 | #include "md5.c" 59 | #endif 60 | 61 | 62 | #ifdef __cplusplus 63 | } /* extern "C" */ 64 | #endif 65 | 66 | #endif /* KLT_MD5_H */ 67 | -------------------------------------------------------------------------------- /examples/kc/helpers/sha1.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef KLT_SHA1_H 17 | #define KLT_SHA1_H 18 | 19 | #ifndef INCLUDED_STDINT_H 20 | #define INCLUDED_STDINT_H 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | struct sha1_inner_state { 29 | uint32_t w[80]; 30 | uint32_t h0, h1, h2, h3, h4; 31 | uint64_t message_bit_length; 32 | int current_w_index; 33 | uint32_t current_w; 34 | }; 35 | 36 | /* If KLT_SHA1_INVISIBLE_LINKAGE is defined, including "sha1.h" will not only 37 | * declare but also define (as static) the implementation */ 38 | #ifdef KLT_SHA1_INVISIBLE_LINKAGE 39 | #define KLT_SHA1_OPTIONAL_STATIC static 40 | #else 41 | #define KLT_SHA1_OPTIONAL_STATIC 42 | #endif 43 | 44 | /* Initializes the state for computing a SHA1 value */ 45 | KLT_SHA1_OPTIONAL_STATIC void sha1_init(struct sha1_inner_state *state); 46 | 47 | /* Processes message data for the SHA1 being computed in state. This function 48 | * can be called multiple times in succession for consecutive parts of the 49 | * same message. 50 | * Returns 0 upon success, or -1 upon failure (which only happens when a 64 51 | * bit message length field expressed in bits overflows.) */ 52 | KLT_SHA1_OPTIONAL_STATIC int sha1_process(struct sha1_inner_state *state, const void *message_part, size_t message_part_size); 53 | 54 | /* Completes the computation of the SHA1 hash and writes it to the 20 bytes 55 | * at digest. Returns 0 upon success, or -1 upon failure (which only happens 56 | * when a 64 bit message length field expressed in bits overflows.) */ 57 | KLT_SHA1_OPTIONAL_STATIC int sha1_finish(struct sha1_inner_state *state, uint8_t *digest); 58 | 59 | #ifdef KLT_SHA1_INVISIBLE_LINKAGE 60 | #include "sha1.c" 61 | #endif 62 | 63 | #ifdef __cplusplus 64 | } /* extern "C" */ 65 | #endif 66 | 67 | #endif /* KLT_SHA1_H */ 68 | -------------------------------------------------------------------------------- /examples/kc/helpers/sha256.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef KLT_SHA256_H 17 | #define KLT_SHA256_H 18 | 19 | #ifndef INCLUDED_STDINT_H 20 | #define INCLUDED_STDINT_H 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | struct sha256_inner_state { 29 | uint32_t w[64]; 30 | uint32_t h0, h1, h2, h3, h4, h5, h6, h7; 31 | uint64_t message_bit_length; 32 | int current_w_index; 33 | uint32_t current_w; 34 | }; 35 | 36 | /* If KLT_SHA256_INVISIBLE_LINKAGE is defined, including "sha256.h" will not only 37 | * declare but also define (as static) the implementation */ 38 | #ifdef KLT_SHA256_INVISIBLE_LINKAGE 39 | #define KLT_SHA256_OPTIONAL_STATIC static 40 | #else 41 | #define KLT_SHA256_OPTIONAL_STATIC 42 | #endif 43 | 44 | /* Initializes the state for computing a SHA256 value */ 45 | KLT_SHA256_OPTIONAL_STATIC void sha256_init(struct sha256_inner_state *state); 46 | 47 | /* Processes message data for the SHA256 being computed in state. This function 48 | * can be called multiple times in succession for consecutive parts of the same 49 | * message. 50 | * Returns 0 upon success, or -1 upon failure (only happens when a 64 bit 51 | * message length field expressed in bits overflows.) */ 52 | KLT_SHA256_OPTIONAL_STATIC int sha256_process(struct sha256_inner_state *state, const void *message_part, size_t message_part_size); 53 | 54 | /* Completes computation of the SHA256 hash and writes it to the 32 bytes at 55 | * digest. Returns 0 upon success, or -1 upon failure (only happens when a 64 56 | * bit message length field expressed in bits overflows.) */ 57 | KLT_SHA256_OPTIONAL_STATIC int sha256_finish(struct sha256_inner_state *state, uint8_t *digest); 58 | 59 | /* Computes the HMAC using SHA256 of key and message and writes it to the 32 60 | * bytes at hmac. */ 61 | KLT_SHA256_OPTIONAL_STATIC int sha256_hmac(const void *key, size_t key_size, const void *message, size_t message_size, uint8_t *hmac); 62 | 63 | #ifdef KLT_SHA256_INVISIBLE_LINKAGE 64 | #include "sha256.c" 65 | #endif 66 | 67 | 68 | #ifdef __cplusplus 69 | } /* extern "C" */ 70 | #endif 71 | 72 | #endif /* KLT_SHA256_H */ 73 | -------------------------------------------------------------------------------- /examples/kc/helpers/unicode_data.h: -------------------------------------------------------------------------------- 1 | /* generated by gen_unicode_data.c */ 2 | 3 | #ifndef UNICODE_DATA_H 4 | #define UNICODE_DATA_H 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | enum UnicodeCategory { 11 | UCCG_INVALID, /* Invalid unicode codepoint */ 12 | UCCG_LU, 13 | UCCG_LL, 14 | UCCG_LT, 15 | UCCG_LM, 16 | UCCG_LO, 17 | UCCG_MN, 18 | UCCG_MC, 19 | UCCG_ME, 20 | UCCG_ND, 21 | UCCG_NL, 22 | UCCG_NO, 23 | UCCG_PC, 24 | UCCG_PD, 25 | UCCG_PS, 26 | UCCG_PE, 27 | UCCG_PI, 28 | UCCG_PF, 29 | UCCG_PO, 30 | UCCG_SM, 31 | UCCG_SC, 32 | UCCG_SK, 33 | UCCG_SO, 34 | UCCG_ZS, 35 | UCCG_ZL, 36 | UCCG_ZP, 37 | UCCG_CC, 38 | UCCG_CF, 39 | UCCG_CS, 40 | UCCG_CO, 41 | UCCG_CN, 42 | }; 43 | /* index by codepoint/256; value is -1 if the range is described by a more 44 | ** detailed map, found at unicode_precise_category_map_lookup[codepoint/256]. 45 | ** If all codepoints in the /256 range have the same category, it is listed 46 | ** in unicode_granular_category_map directly. 47 | ** If all codepoints in the /256 range have the same category, then 48 | ** unicode_precise_category_map_lookup[codepoint/256] will be NULL. 49 | */ 50 | extern signed char unicode_granular_category_map[]; 51 | extern signed char *unicode_precise_category_map_lookup[]; 52 | 53 | #ifdef __cplusplus 54 | } /* extern "C" */ 55 | #endif 56 | 57 | #endif /* UNICODE_DATA_H */ 58 | -------------------------------------------------------------------------------- /examples/kc/src/data_section.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef STDLIB_H_INCLUDED 17 | #define STDLIB_H_INCLUDED 18 | #include 19 | #endif 20 | 21 | #ifndef STRING_H_INCLUDED 22 | #define STRING_H_INCLUDED 23 | #include 24 | #endif 25 | 26 | #ifndef DATA_SECTION_H_INCLUDED 27 | #define DATA_SECTION_H_INCLUDED 28 | #include "data_section.h" 29 | #endif 30 | 31 | void ds_init(struct data_section *ds) { 32 | ds->portions_ = NULL; 33 | } 34 | 35 | void ds_cleanup(struct data_section *ds) { 36 | struct ds_portion *dsp = ds->portions_; 37 | if (dsp) { 38 | struct ds_portion *next = dsp->chain_; 39 | do { 40 | dsp = next; 41 | next = dsp->chain_; 42 | 43 | if (dsp->data_) { 44 | free(dsp->data_); 45 | } 46 | free(dsp); 47 | 48 | } while (dsp != ds->portions_); 49 | } 50 | } 51 | 52 | 53 | struct ds_portion *ds_alloc_portion(struct data_section *ds) { 54 | struct ds_portion *dsp = (struct ds_portion *)malloc(sizeof(struct ds_portion)); 55 | if (ds->portions_) { 56 | dsp->chain_ = ds->portions_->chain_; 57 | ds->portions_->chain_ = dsp; 58 | ds->portions_ = dsp; 59 | } 60 | else { 61 | dsp->chain_ = dsp; 62 | ds->portions_ = dsp; 63 | } 64 | dsp->data_ = NULL; 65 | dsp->size_ = 0; 66 | dsp->size_allocated_ = 0; 67 | return dsp; 68 | } 69 | 70 | int ds_reserve(struct ds_portion *dsp, size_t num_bytes, void **pbuf) { 71 | size_t size_needed = dsp->size_ + num_bytes; 72 | if (size_needed < num_bytes) { 73 | return -1; /* overflow */ 74 | } 75 | if (size_needed > dsp->size_allocated_) { 76 | size_t size_to_allocate = dsp->size_allocated_ + dsp->size_allocated_ + 1; 77 | if (size_to_allocate <= dsp->size_allocated_) { 78 | return -1; /* overflow / maximum size_t exceeded. */ 79 | } 80 | if (size_to_allocate < size_needed) { 81 | size_to_allocate = size_needed; 82 | } 83 | void *buf = realloc(dsp->data_, size_to_allocate); 84 | if (!buf) { 85 | return -2; /* no mem */ 86 | } 87 | memset(((char *)buf) + dsp->size_allocated_, 0, (size_to_allocate - dsp->size_allocated_)); 88 | dsp->data_ = buf; 89 | dsp->size_allocated_ = size_to_allocate; 90 | } 91 | *pbuf = ((char *)dsp->data_) + dsp->size_; 92 | dsp->size_ += num_bytes; 93 | return 0; 94 | } 95 | 96 | int ds_append(struct ds_portion *dsp, size_t num_bytes, void *bytes) { 97 | int r; 98 | void *buf; 99 | r = ds_reserve(dsp, num_bytes, &buf); 100 | if (r) return r; 101 | memcpy(((char *)dsp->data_) + dsp->size_, bytes, num_bytes); 102 | return 0; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /examples/kc/src/data_section.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef DATA_SECTION_H 17 | #define DATA_SECTION_H 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /* A portion is 0 or more consecutive bytes in the data section. */ 24 | struct ds_portion { 25 | struct ds_portion *chain_; 26 | size_t size_; 27 | size_t size_allocated_; 28 | void *data_; 29 | }; 30 | 31 | /* A datasection consists of portions which, together, describes all 32 | * the data in the datasection. */ 33 | struct data_section { 34 | struct ds_portion *portions_; /* tail cyclic */ 35 | }; 36 | 37 | void ds_init(struct data_section *ds); 38 | void ds_cleanup(struct data_section *ds); 39 | 40 | struct ds_portion *ds_alloc_portion(struct data_section *ds); 41 | 42 | int ds_reserve(struct ds_portion *dsp, size_t num_bytes, void **buf); 43 | int ds_append(struct ds_portion *dsp, size_t num_bytes, void *bytes); 44 | 45 | 46 | #ifdef __cplusplus 47 | } /* extern "C" */ 48 | #endif 49 | 50 | #endif /* DATA_SECTION_H */ 51 | -------------------------------------------------------------------------------- /examples/kc/src/dynamic_runtime_linking.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef STDLIB_H_INCLUDED 17 | #define STDLIB_H_INCLUDED 18 | #include 19 | #endif 20 | 21 | #ifndef STDIO_H_INCLUDED 22 | #define STDIO_H_INCLUDED 23 | #include 24 | #endif 25 | 26 | #ifndef STRING_H_INCLUDED 27 | #define STRING_H_INCLUDED 28 | #include 29 | #endif 30 | 31 | #ifndef STDINT_H_INCLUDED 32 | #define STDINT_H_INCLUDED 33 | #include 34 | #endif 35 | 36 | #ifndef C_COMPILER_H_INCLUDED 37 | #define C_COMPILER_H_INCLUDED 38 | #include "c_compiler.h" 39 | #endif 40 | 41 | #ifndef DECL_H_INCLUDED 42 | #define DECL_H_INCLUDED 43 | #include "decl.h" 44 | #endif 45 | 46 | #ifndef DYNAMIC_RUNTIME_LINKING_H_INCLUDED 47 | #define DYNAMIC_RUNTIME_LINKING_H_INCLUDED 48 | #include "dynamic_runtime_linking.h" 49 | #endif 50 | 51 | static struct c_compiler *g_cc_handle_for_printf_ = NULL; 52 | 53 | static int drl_printf(const char *fmt, ...) { 54 | int r; 55 | va_list args; 56 | if (!g_cc_handle_for_printf_) return -1; 57 | va_start(args, fmt); 58 | r = g_cc_handle_for_printf_->vprintf_handler(g_cc_handle_for_printf_->vprintf_baton_, NULL, 0, fmt, args); 59 | va_end(args); 60 | return r; 61 | } 62 | 63 | int drl_resolve_sym(struct c_compiler *cc, struct decl *d, void **ptr) { 64 | *ptr = NULL; 65 | 66 | struct cc_link_name *name = NULL; 67 | name = (struct cc_link_name *)st_find(&cc->link_table_, d->sym_.ident_); 68 | if (name) { 69 | *ptr = name->ptr_; 70 | return 0; 71 | } 72 | 73 | if (!strcmp("printf", d->sym_.ident_)) { 74 | /* XXX: Not thread-safe */ 75 | g_cc_handle_for_printf_ = cc; 76 | *ptr = (void *)drl_printf; 77 | return 0; 78 | } 79 | 80 | return -1; 81 | } 82 | 83 | int drl_register_sym(struct c_compiler *cc, const char *link_name, void *ptr) { 84 | struct cc_link_name *name = NULL; 85 | int is_new = 0; 86 | name = (struct cc_link_name *)st_find_or_insert(&cc->link_table_, link_name, &is_new, sizeof(*name)); 87 | if (!name) return -1; 88 | /* It's fine to overwrite an existing pointer value with a different one (no need to check is_new) */ 89 | name->ptr_ = ptr; 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /examples/kc/src/dynamic_runtime_linking.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef DYNAMIC_RUNTIME_LINKING_H 17 | #define DYNAMIC_RUNTIME_LINKING_H 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /* Resolving symbols at runtime when running C code interpretively */ 24 | 25 | struct c_compiler; 26 | struct decl; 27 | 28 | int drl_resolve_sym(struct c_compiler *cc, struct decl *d, void **ptr); 29 | int drl_register_sym(struct c_compiler *cc, const char *link_name, void *ptr); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif /* DYNAMIC_RUNTIME_LINKING_H */ 36 | -------------------------------------------------------------------------------- /examples/kc/src/func_def.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FUNC_DEF_H 17 | #define FUNC_DEF_H 18 | 19 | #ifndef DECL_H_INCLUDED 20 | #define DECL_H_INCLUDED 21 | #include "decl.h" 22 | #endif 23 | 24 | #ifndef STMT_H_INCLUDED 25 | #define STMT_H_INCLUDED 26 | #include "stmt.h" 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | struct c_compiler; 34 | 35 | struct func_def { 36 | struct decl d_; 37 | 38 | struct stmt *body_; 39 | 40 | uint64_t stackframe_size_required_; 41 | uint64_t parameter_size_required_; 42 | }; 43 | 44 | struct func_def *func_def_alloc(struct name_space *ns, int *already_exists, const char *ident, struct situs *ident_loc, sc_storage_class_t sc, int function_specifiers, struct type_node *tn); 45 | 46 | /* Assigns decl::local_offset_ for all local variables in the function and, in doing so, determines fd->stackframe_size_required_ */ 47 | int func_def_realize_locals(struct c_compiler *cc, struct func_def *fd); 48 | 49 | #ifdef __cplusplus 50 | } /* extern "C" */ 51 | #endif 52 | 53 | #endif /* FUNC_DEF_H */ 54 | -------------------------------------------------------------------------------- /examples/kc/src/invoke_call_x64.asm: -------------------------------------------------------------------------------- 1 | ; Copyright 2023-2025 Kinglet B.V. 2 | ; 3 | ; Licensed under the Apache License, Version 2.0 (the "License"); 4 | ; you may not use this file except in compliance with the License. 5 | ; You may obtain a copy of the License at 6 | ; 7 | ; http://www.apache.org/licenses/LICENSE-2.0 8 | ; 9 | ; Unless required by applicable law or agreed to in writing, software 10 | ; distributed under the License is distributed on an "AS IS" BASIS, 11 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ; See the License for the specific language governing permissions and 13 | ; limitations under the License. 14 | 15 | _DATA SEGMENT 16 | hello_msg db "Hello world", 0 17 | _DATA ENDS 18 | 19 | PUBLIC invoke_call_x64 20 | PUBLIC enter_call_tramp_x64 21 | PUBLIC enter_call_x64 22 | EXTERN invoke_enter_call:proto 23 | 24 | _TEXT SEGMENT 25 | 26 | Invocation STRUCT 27 | rcx_ QWORD ? 28 | rdx_ QWORD ? 29 | r8_ QWORD ? 30 | r9_ QWORD ? 31 | xmm0_ QWORD ? 32 | xmm1_ QWORD ? 33 | xmm2_ QWORD ? 34 | xmm3_ QWORD ? 35 | fnptr_ QWORD ? 36 | rax_result_ QWORD ? 37 | hspace_size_ QWORD ? 38 | hspace_ QWORD ? 39 | Invocation ENDS 40 | 41 | invoke_call_x64 PROC FRAME 42 | push rdi 43 | .pushreg rdi 44 | push rsi 45 | .pushreg rsi 46 | push rbp 47 | .pushreg rbp 48 | push r12 49 | .pushreg r12 50 | mov r12, rsp 51 | .setframe r12, 0 ; nominate r12 as the frame pointer - this is needed because the stackframe is dynamic in size (hspace_size_ is variable) 52 | sub rsp, 8 * (2) + 8 * 4 + 8 53 | .allocstack 8 * (2) + 8 * 4 + 8 54 | lea rbp, [rsp + 8 * 2 + 8 * 4 + 8] 55 | 56 | .endprolog 57 | sub rsp, [rcx.Invocation].hspace_size_ 58 | 59 | mov [rbp - 16], rcx 60 | 61 | mov rsi, [rcx.Invocation].hspace_ 62 | mov rcx, [rcx.Invocation].hspace_size_ 63 | mov rdi, rsp 64 | rep movsb 65 | 66 | mov rcx, [rbp - 16] 67 | mov r10, qword ptr [rcx.Invocation].fnptr_ 68 | 69 | movsd xmm3, qword ptr [rcx.Invocation].xmm3_ 70 | movsd xmm2, qword ptr [rcx.Invocation].xmm2_ 71 | movsd xmm1, qword ptr [rcx.Invocation].xmm1_ 72 | movsd xmm0, qword ptr [rcx.Invocation].xmm0_ 73 | 74 | mov r9, qword ptr [rcx.Invocation].r9_ 75 | mov r8, qword ptr [rcx.Invocation].r8_ 76 | mov rdx, qword ptr [rcx.Invocation].rdx_ 77 | mov rcx, qword ptr [rcx.Invocation].rcx_ 78 | 79 | ; Variable stack block - rep stos the data onto the stack. For consistency's sake this may just include the 4*8 as well as 80 | ; that would move a lot of the call logic into C country 81 | 82 | ; jump to [rcx.Invocation].fnptr_ 83 | call r10 84 | 85 | mov rcx, [rbp - 16] 86 | mov [rcx.Invocation].rax_result_, rax 87 | 88 | add rsp, [rcx.Invocation].hspace_size_ 89 | 90 | add rsp, 8 * (2) + 8 * 4 + 8 91 | pop r12 92 | pop rbp 93 | pop rsi 94 | pop rdi 95 | ret 96 | invoke_call_x64 ENDP 97 | 98 | enter_call_tramp_x64 PROC 99 | mov r11, 123h 100 | mov r10, 1234123412341234h 101 | jmp enter_call_x64 102 | enter_call_tramp_x64 ENDP 103 | 104 | db 123 105 | 106 | enter_call_x64 PROC FRAME 107 | push rbp ; Odd-aligned on entry, push rbp even-aligns us. 108 | .pushreg rbp 109 | sub rsp, SIZEOF Invocation + 8*4 ; 8 * 4 is for register parameter stack area on subsequent CALLs inside this function. 110 | .allocstack SIZEOF Invocation + 8*4 111 | .endprolog 112 | lea rax, [rsp + SIZEOF Invocation + 8 + 8*4] 113 | mov [8*4 + rsp.Invocation].rcx_, rcx 114 | mov [8*4 + rsp.Invocation].rdx_, rdx 115 | mov [8*4 + rsp.Invocation].r8_, r8 116 | mov [8*4 + rsp.Invocation].r9_, r9 117 | movsd [8*4 + rsp.Invocation].xmm0_, xmm0 118 | movsd [8*4 + rsp.Invocation].xmm1_, xmm1 119 | movsd [8*4 + rsp.Invocation].xmm2_, xmm2 120 | movsd [8*4 + rsp.Invocation].xmm3_, xmm3 121 | lea rcx, [8 * 4 + rsp] 122 | ; mov rcx, rsp 123 | mov rdx, rax 124 | mov r8, r10 125 | mov r9, r11 126 | call invoke_enter_call 127 | mov rax, [8 * 4 + rsp.Invocation].rax_result_ 128 | add rsp, SIZEOF Invocation + 8*4 129 | pop rbp 130 | ret 131 | enter_call_x64 ENDP 132 | 133 | _TEXT ENDS 134 | 135 | END 136 | -------------------------------------------------------------------------------- /examples/kc/src/invoke_x64.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef TYPES_H_INCLUDED 17 | #define TYPES_H_INCLUDED 18 | #include "types.h" 19 | #endif 20 | 21 | #ifndef EXPR_H_INCLUDED 22 | #define EXPR_H_INCLUDED 23 | #include "expr.h" 24 | #endif 25 | 26 | struct c_compiler; 27 | 28 | void invoke_init(void); 29 | void invoke_cleanup(void); 30 | void *invoke_alloc_function_entry(struct c_compiler *cc, struct func_def *fd); 31 | 32 | int invoke_x64(struct c_compiler *cc, struct expr *x, struct expr_temp *temps); 33 | -------------------------------------------------------------------------------- /examples/kc/src/jitmem.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef JITMEM_H 17 | #define JITMEM_H 18 | 19 | #ifndef STDLIB_H_INCLUDED 20 | #define STDLIB_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | struct c_compiler; 29 | 30 | void jitmem_init(void); 31 | void jitmem_cleanup(void); 32 | 33 | /* Reserves num_bytes of JIT memory and returns a pointer to it. 34 | * Note that this is a *reservation*; consecutive jitmem_reserve() 35 | * calls will return the same pointer! It still needs to be 36 | * acquired using jitmem_acquire(). 37 | * jitmem_reserve is useful if the JIT code is not position 38 | * independant but needs to know the pointer of the memory. 39 | * Note that the returned pointer is write-protected and executable, 40 | * you should use jitmem_acquire() to copy data into jit memory. 41 | */ 42 | void *jitmem_reserve(struct c_compiler *cc, size_t num_bytes); 43 | 44 | /* Allocates and returns num_bytes of jit memory, if the num_bytes 45 | * value is the same, then it returns the same pointer as any 46 | * preceeding jitmem_reserve() call. Calling jitmem_reserve() before 47 | * jitmem_acquire() is however optional, and only required if you 48 | * need to know the pointer before initializing the data at it. 49 | * The memory returned is initialized with num_bytes of data at the 50 | * data pointer. 51 | * Note that the returned pointer is write-protected and executable. 52 | */ 53 | void *jitmem_acquire(struct c_compiler *cc, size_t num_bytes, const void *data); 54 | 55 | 56 | #ifdef __cplusplus 57 | } /* extern "C" */ 58 | #endif 59 | 60 | #endif /* JITMEM_H */ 61 | 62 | -------------------------------------------------------------------------------- /examples/kc/src/name_space.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef STDIO_H_INCLUDED 17 | #define STDIO_H_INCLUDED 18 | #include 19 | #endif 20 | 21 | #ifndef STDLIB_H_INCLUDED 22 | #define STDLIB_H_INCLUDED 23 | #include 24 | #endif 25 | 26 | #ifndef STRING_H_INCLUDED 27 | #define STRING_H_INCLUDED 28 | #include 29 | #endif 30 | 31 | #ifndef HELPERS_H_INCLUDED 32 | #define HELPERS_H_INCLUDED 33 | #include "helpers.h" 34 | #endif 35 | 36 | #ifndef KLT_LOGGER_H_INCLUDED 37 | #define KLT_LOGGER_H_INCLUDED 38 | #define KLT_LOG_MODULE "symtab" 39 | #include "klt_logger.h" 40 | #endif 41 | 42 | #ifndef NAME_SPACE_H_INCLUDED 43 | #define NAME_SPACE_H_INCLUDED 44 | #include "name_space.h" 45 | #endif 46 | 47 | 48 | void ns_init(struct name_space *ns) { 49 | ns->parent_ = NULL; 50 | 51 | st_init(&ns->ordinary_idents_); 52 | st_init(&ns->struct_tags_); 53 | st_init(&ns->union_tags_); 54 | st_init(&ns->enum_tags_); 55 | st_init(&ns->stmt_labels_); 56 | } 57 | 58 | void ns_cleanup(struct name_space *ns) { 59 | st_cleanup(&ns->ordinary_idents_); 60 | st_cleanup(&ns->struct_tags_); 61 | st_cleanup(&ns->union_tags_); 62 | st_cleanup(&ns->enum_tags_); 63 | st_cleanup(&ns->stmt_labels_); 64 | } 65 | 66 | struct sym *ns_find_ordinary_ident(struct name_space *ns, const char *id) { 67 | struct sym *s; 68 | do { 69 | s = st_find(&ns->ordinary_idents_, id); 70 | if (s) return s; 71 | ns = ns->parent_; 72 | } while (ns); 73 | 74 | return NULL; 75 | } 76 | 77 | struct ns_tagged_type_sym *ns_find_struct(struct name_space *ns, const char *id) { 78 | struct sym *s; 79 | do { 80 | s = st_find(&ns->struct_tags_, id); 81 | if (s) return (struct ns_tagged_type_sym *)s; 82 | ns = ns->parent_; 83 | } while (ns); 84 | 85 | return NULL; 86 | } 87 | 88 | struct ns_tagged_type_sym *ns_find_union(struct name_space *ns, const char *id) { 89 | struct sym *s; 90 | do { 91 | s = st_find(&ns->union_tags_, id); 92 | if (s) return (struct ns_tagged_type_sym *)s; 93 | ns = ns->parent_; 94 | } while (ns); 95 | 96 | return NULL; 97 | } 98 | 99 | struct ns_tagged_type_sym *ns_find_enum(struct name_space *ns, const char *id) { 100 | struct sym *s; 101 | do { 102 | s = st_find(&ns->enum_tags_, id); 103 | if (s) return (struct ns_tagged_type_sym *)s; 104 | ns = ns->parent_; 105 | } while (ns); 106 | 107 | return NULL; 108 | } 109 | -------------------------------------------------------------------------------- /examples/kc/src/name_space.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef NAME_SPACE_H 17 | #define NAME_SPACE_H 18 | 19 | #ifndef SYMTAB_H_INCLUDED 20 | #define SYMTAB_H_INCLUDED 21 | #include "symtab.h" 22 | #endif 23 | 24 | #ifndef TYPES_H_INCLUDED 25 | #define TYPES_H_INCLUDED 26 | #include "types.h" 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | struct name_space { 34 | struct name_space *parent_; 35 | 36 | struct symtab ordinary_idents_; 37 | struct symtab struct_tags_; 38 | struct symtab union_tags_; 39 | struct symtab enum_tags_; 40 | struct symtab stmt_labels_; 41 | }; 42 | 43 | struct ns_label_sym { 44 | struct sym sym_; 45 | struct stmt *labeled_stmt_; 46 | }; 47 | 48 | struct ns_tagged_type_sym { 49 | struct sym sym_; 50 | struct type_node *type_; 51 | }; 52 | 53 | void ns_init(struct name_space *ns); 54 | void ns_cleanup(struct name_space *ns); 55 | 56 | struct sym *ns_find_ordinary_ident(struct name_space *ns, const char *id); 57 | struct ns_tagged_type_sym *ns_find_struct(struct name_space *ns, const char *id); 58 | struct ns_tagged_type_sym *ns_find_union(struct name_space *ns, const char *id); 59 | struct ns_tagged_type_sym *ns_find_enum(struct name_space *ns, const char *id); 60 | 61 | 62 | #ifdef __cplusplus 63 | } /* extern "C" */ 64 | #endif 65 | 66 | #endif /* NAME_SPACE_H */ 67 | -------------------------------------------------------------------------------- /examples/kc/src/pp_line_continuations.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | 17 | #ifndef STDLIB_H_INCLUDED 18 | #define STDLIB_H_INCLUDED 19 | #include 20 | #endif 21 | 22 | #ifndef STRING_H_INCLUDED 23 | #define STRING_H_INCLUDED 24 | #include 25 | #endif 26 | 27 | struct c_compiler; 28 | 29 | #ifndef C_COMPILER_H_INCLUDED 30 | #define C_COMPILER_H_INCLUDED 31 | #include "c_compiler.h" 32 | #endif 33 | 34 | #ifndef SITUS_H_INCLUDED 35 | #define SITUS_H_INCLUDED 36 | #include "situs.h" 37 | #endif 38 | 39 | %scanner% 40 | 41 | %prefix pplc_ 42 | 43 | %common_type struct situs 44 | %constructor situs_init(&$$); 45 | %destructor situs_cleanup(&$$); 46 | 47 | %params struct c_compiler *cc, char **output_buf, size_t *output_end, size_t *output_buf_alloc_size, struct situs *output_situs, struct situs *input_situs 48 | 49 | $: { 50 | situs_move_range(&$, input_situs, $endoffset - $offset, $text); 51 | } 52 | 53 | : \n|[^\n]*[^\\\n]\n { 54 | /* Any line that does not end in a continuation (no \ at the end) */ 55 | if (cc_pp_concat_output_b(cc, output_situs, output_buf, output_end, output_buf_alloc_size, &$, $text, $len)) { 56 | return _PPLC_NO_MEMORY; 57 | } 58 | } 59 | 60 | : [^\n]*[^\\\n]\Z { 61 | /* Any line that ends at the end of input. */ 62 | if (cc_pp_concat_output_b(cc, output_situs, output_buf, output_end, output_buf_alloc_size, &$, $text, $len)) { 63 | return _PPLC_NO_MEMORY; 64 | } 65 | } 66 | 67 | : \Z { 68 | /* An empty line at the end of input */ 69 | } 70 | 71 | : \n { 72 | /* A regular newline */ 73 | if (cc_pp_concat_output_b(cc, output_situs, output_buf, output_end, output_buf_alloc_size, &$, $text, $len)) { 74 | return _PPLC_NO_MEMORY; 75 | } 76 | } 77 | 78 | : \\\n { 79 | /* A line continuation - we eat these */ 80 | } 81 | 82 | : [^\n]*\\\Z { 83 | /* Line at the end of input ending with a line continuation */ 84 | if (cc_pp_concat_output_b(cc, output_situs, output_buf, output_end, output_buf_alloc_size, &$, $text, $len)) { 85 | return _PPLC_NO_MEMORY; 86 | } 87 | } 88 | 89 | : [^\n]* [^\\\n] { 90 | /* Any line that does not end on a backslash or a newline. Given that other patterns will include the newline 91 | * or the end of file (and are therefore longer), this can only match lines that are part of linecontinuations. */ 92 | /* A line that ends in a line continuation */ 93 | if (cc_pp_concat_output_b(cc, output_situs, output_buf, output_end, output_buf_alloc_size, &$, $text, $len)) { 94 | return _PPLC_NO_MEMORY; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /examples/kc/src/pplinedirectives.cbrt: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STDIO_H_INCLUDED 3 | #define STDIO_H_INCLUDED 4 | #include 5 | #endif 6 | 7 | #ifndef STDLIB_H_INCLUDED 8 | #define STDLIB_H_INCLUDED 9 | #include 10 | #endif 11 | 12 | #ifndef STDINT_H_INCLUDED 13 | #define STDINT_H_INCLUDED 14 | #include 15 | #endif 16 | 17 | #ifndef STRING_H_INCLUDED 18 | #define STRING_H_INCLUDED 19 | #include 20 | #endif 21 | 22 | #ifndef ASSERT_H_INCLUDED 23 | #define ASSERT_H_INCLUDED 24 | #include 25 | #endif 26 | 27 | #ifndef STMT_H_INCLUDED 28 | #define STMT_H_INCLUDED 29 | #include "stmt.h" 30 | #endif 31 | 32 | #ifndef EXPR_H_INCLUDED 33 | #define EXPR_H_INCLUDED 34 | #include "expr.h" 35 | #endif 36 | 37 | #ifndef TYPES_H_INCLUDED 38 | #define TYPES_H_INCLUDED 39 | #include "types.h" 40 | #endif 41 | 42 | #ifndef TEMPL_PARSER_H_INCLUDED 43 | #define TEMPL_PARSER_H_INCLUDED 44 | #include "templ_parser.h" 45 | #endif 46 | 47 | #ifndef SCAN_HELPERS_H_INCLUDED 48 | #define SCAN_HELPERS_H_INCLUDED 49 | #include "scan_helpers.h" 50 | #endif 51 | 52 | %grammar% 53 | 54 | %token BANG TILDE PERCENT PERCENT_EQUALS AMPERSAND AMPERSAND_AMPERSAND AMPERSAND_EQUALS PAR_OPEN PAR_CLOSE 55 | %token ASTERISK ASTERISK_EQUALS PLUS PLUS_PLUS PLUS_EQUALS COMMA MINUS MINUS_MINUS MINUS_EQUALS 56 | %token DOT DOT_DOT_DOT SLASH SLASH_EQUALS COLON SEMICOLON LT LT_LT LT_LT_EQUALS LT_EQUALS 57 | %token EQUALS EQUALS_EQUALS BANG_EQUALS GT GT_EQUALS GT_GT GT_GT_EQUALS 58 | %token ARROW SQBRACE_OPEN SQBRACE_CLOSE CARET CARET_EQUALS CUBRACE_OPEN CUBRACE_CLOSE 59 | %token BAR BAR_EQUALS BAR_BAR QUESTION_MARK 60 | %token AUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM EXTERN FLOAT FOR GOTO IF INLINE INT LONG 61 | %token REGISTER RESTRICT RETURN SHORT SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE 62 | %token WHILE 63 | %token BOOL COMPLEX IMAGINARY 64 | %token INTEGER_LIT FLOAT_LIT STRING_LIT CHAR_LIT IDENT WHITESPACE 65 | 66 | 67 | -------------------------------------------------------------------------------- /examples/kc/src/scan_helpers.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef SCAN_HELPERS_H 17 | #define SCAN_HELPERS_H 18 | 19 | #ifndef STDINT_H_INCLUDED 20 | #define STDINT_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | struct c_compiler; 29 | struct situs; 30 | 31 | /* WARNING: These are not general use functions, instead they factor out functionality that would 32 | * otherwise be replicated in pattern action code. The input already has to meticulously 33 | * match the pattern expected by the function, or results will be unpredictable / wrong. */ 34 | 35 | int sch_parse_decimal(struct c_compiler *cc, uint64_t *pval, const char *text, size_t len, struct situs *loc); 36 | int sch_parse_octal(struct c_compiler *cc, uint64_t *pval, const char *text, size_t len, struct situs *loc); 37 | int sch_parse_hexadecimal(struct c_compiler *cc, uint64_t *pval, const char *text, size_t len, struct situs *loc); 38 | int sch_parse_binary(struct c_compiler *cc, uint64_t *pval, const char *text, size_t len, struct situs *loc); 39 | void sch_process_ohb_none(struct c_compiler *cc, uint64_t val, struct expr **expr, struct situs *loc); 40 | void sch_process_ohb_U(struct c_compiler *cc, uint64_t val, struct expr **expr, struct situs *loc); 41 | void sch_process_ohb_L(struct c_compiler *cc, uint64_t val, struct expr **expr, struct situs *loc); 42 | void sch_process_ohb_UL(struct c_compiler *cc, uint64_t val, struct expr **expr, struct situs *loc); 43 | void sch_process_ohb_LL(struct c_compiler *cc, uint64_t val, struct expr **expr, struct situs *loc); 44 | void sch_process_ohb_ULL(struct c_compiler *cc, uint64_t val, struct expr **expr, struct situs *loc); 45 | 46 | void sch_process_pptk_ohb_none(struct c_compiler *cc, struct pptk **pp_chain, const char *text, uint64_t val, struct pptk **pptk, struct situs *loc); 47 | void sch_process_pptk_ohb_U(struct c_compiler *cc, struct pptk **pp_chain, const char *text, uint64_t val, struct pptk **pptk, struct situs *loc); 48 | void sch_process_pptk_ohb_L(struct c_compiler *cc, struct pptk **pp_chain, const char *text, uint64_t val, struct pptk **pptk, struct situs *loc); 49 | void sch_process_pptk_ohb_UL(struct c_compiler *cc, struct pptk **pp_chain, const char *text, uint64_t val, struct pptk **pptk, struct situs *loc); 50 | void sch_process_pptk_ohb_LL(struct c_compiler *cc, struct pptk **pp_chain, const char *text, uint64_t val, struct pptk **pptk, struct situs *loc); 51 | void sch_process_pptk_ohb_ULL(struct c_compiler *cc, struct pptk **pp_chain, const char *text, uint64_t val, struct pptk **pptk, struct situs *loc); 52 | 53 | int sch_read_oct_esc_value(const char *octal_num, int *val); 54 | int sch_read_hex_esc_value(const char *hex_xx_num, int *val); 55 | int sch_read_char_value(struct c_compiler *cc, const char *lit_pos, int *val, int max_char, struct situs *loc, const char *kind); 56 | 57 | 58 | #ifdef __cplusplus 59 | } /* extern "C" */ 60 | #endif 61 | 62 | #endif /* SCAN_HELPERS_H */ 63 | -------------------------------------------------------------------------------- /examples/kc/src/situs.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef SITUS_H 17 | #define SITUS_H 18 | 19 | #ifndef STDDEF_H_INCLUDED 20 | #define STDDEF_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | struct situs_position { 25 | const char *filename_; 26 | size_t offset_; 27 | int line_, col_; 28 | }; 29 | 30 | struct situs_span { 31 | /* Filename of source in which the span appears */ 32 | const char *filename_; 33 | 34 | /* Start and end byte offsets in the original source in which the span appears */ 35 | size_t start_, end_; 36 | 37 | /* Start line and column, both 1 based, of the span of text */ 38 | int start_line_, start_col_; 39 | 40 | /* End line and column, both 1 based, of the span of text */ 41 | int end_line_, end_col_; 42 | 43 | /* If non-zero, this is a substitution, num_bytes_ indicates the size of text the 44 | * original span of text has been substituted by. If false, num_bytes_ is always 45 | * equal to end_ - start_. */ 46 | int is_substitution_ : 1; 47 | 48 | /* For a substitution, the range being substituted may consist of multiple spans 49 | * that are not adjacent. When that is the case, the first has a non-zero num_bytes_, 50 | * and the successive spans have num_bytes_ to 0 with is_aux_ non-zero. */ 51 | int is_aux_ : 1; 52 | 53 | /* Number of bytes of text that this situs_span describes. */ 54 | size_t num_bytes_; 55 | }; 56 | 57 | struct situs_dynamic { 58 | size_t num_spans_allocated_; 59 | struct situs_span *spans_; 60 | }; 61 | 62 | struct situs { 63 | size_t num_spans_; 64 | union { 65 | struct situs_dynamic many_; /* dynamic array if num_spans_ > 1 for mutliple situs spans */ 66 | struct situs_span one_; /* static situs_span if num_spans_ == 1 (which is the likely case for normal sourcecode) */ 67 | } u_; 68 | }; 69 | 70 | void situs_init(struct situs *s); 71 | void situs_cleanup(struct situs *s); 72 | 73 | int situs_move_range(struct situs *to, struct situs *from, size_t byte_length, const char *text); 74 | int situs_clone(struct situs *dst, const struct situs *src); 75 | int situs_concat(struct situs *dsthead, const struct situs *tail); 76 | int situs_skip(struct situs *from, size_t byte_length, const char *text); 77 | 78 | size_t situs_len(const struct situs *s); 79 | 80 | int situs_line(const struct situs *s); 81 | int situs_col(const struct situs *s); 82 | const char *situs_filename(const struct situs *s); 83 | 84 | void situs_convert_to_substitution(struct situs *s, size_t num_bytes); 85 | 86 | /* Initializes situs s to tbe at the point after src_after; the span contains no bytes, 87 | * (so the span's start_ and end_ are identical) but it may represent sourcecode text 88 | * (and hence num_bytes is non-zero). Useful for edge-case situations where code is 89 | * inserted by the compiler. 90 | * Note that the resulting span is always, by definition, a substitution. */ 91 | void situs_init_from_after(struct situs *s, const struct situs *src_after, size_t num_bytes); 92 | 93 | /* Ideally used like C++'s std::swap() in that we can move things without incurring 94 | * memory allocations and still ensuring clean destruction. */ 95 | void situs_swap(struct situs *a, struct situs *b); 96 | 97 | #endif /* SITUS_H */ 98 | -------------------------------------------------------------------------------- /examples/kc/src/stmt.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef STMT_H 17 | #define STMT_H 18 | 19 | #ifndef SITUS_H_INCLUDED 20 | #define SITUS_H_INCLUDED 21 | #include "situs.h" 22 | #endif 23 | 24 | #ifndef SWITCH_H_INCLUDED 25 | #define SWITCH_H_INCLUDED 26 | #include "switch.h" 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | struct c_compiler; 34 | struct expr; 35 | 36 | enum stmt_type { 37 | ST_LABEL, 38 | ST_CASE, 39 | ST_DEFAULT, 40 | ST_BLOCK, 41 | ST_EXPR, 42 | ST_IF, 43 | ST_IF_ELSE, 44 | ST_SWITCH, 45 | ST_WHILE, 46 | ST_DO_WHILE, 47 | ST_FOR, 48 | ST_GOTO, 49 | ST_CONTINUE, 50 | ST_BREAK, 51 | ST_RETURN, 52 | ST_NOP 53 | }; 54 | 55 | struct stmt { 56 | enum stmt_type type_; 57 | struct situs location_; /* location for issuing errors (eg. typically the keyword) */ 58 | 59 | struct stmt *parent_; 60 | struct stmt *next_, *prev_; 61 | 62 | struct stmt *parent_block_; /* parent block context when allocating ST_BLOCK preemptively in anticipation of its use */ 63 | 64 | struct stmt *child0_; /* true branch for if, if-else, children for others, declaration for "for (decl; exp; exp)" */ 65 | struct stmt *child1_; /* false branch for if-else */ 66 | struct situs label_range_; /* location for the label, if there is one. */ 67 | char *label_; /* label for both label and goto */ 68 | 69 | struct name_space *ns_; /* namespace of block if type_ == ST_BLOCK. */ 70 | 71 | /* expression is absent if start_ == end_ (eg. both "for (;;)" and "return;" have absent expressions) */ 72 | struct expr *expr0_; 73 | struct expr *expr1_; 74 | struct expr *expr2_; 75 | 76 | /* Pointer to the switch-stmt that is a parent of this statement, or NULL if this is not a 77 | * ST_CASE, ST_DEFAULT or ST_SWITCH statement, or there is no parent. */ 78 | struct stmt *parent_switch_; 79 | 80 | /* Same as parent_switch but for break statements (meaning it is impacted by switches and loops) */ 81 | struct stmt *break_parent_; 82 | 83 | /* Same as parent_switch but for continue statements (meaning it is impacted only by loops) */ 84 | struct stmt *continue_parent_; 85 | 86 | /* All case statements linked up to this switch (this must be a ST_SWITCH). */ 87 | struct switch_case_map cases_; 88 | 89 | /* Goto destination statement (this must be an ST_GOTO.) */ 90 | struct stmt *goto_destination_; 91 | }; 92 | 93 | struct stmt *stmt_alloc(struct c_compiler *cc, enum stmt_type st, struct situs *location); 94 | void stmt_free(struct stmt *s); 95 | void stmt_set_parent(struct stmt *s, struct stmt *new_parent); 96 | 97 | int stmt_prepare(struct c_compiler *cc, struct stmt *root); 98 | int stmt_exec(struct c_compiler *cc, struct stmt *root, void *local_base, void *param_base, void *return_value_ptr); 99 | 100 | #ifdef __cplusplus 101 | } /* extern "C" */ 102 | #endif 103 | 104 | #endif /* STMT_H */ 105 | -------------------------------------------------------------------------------- /examples/kc/src/switch.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef SWITCH_H 17 | #define SWITCH_H 18 | 19 | #ifndef STDINT_H_INCLUDED 20 | #define STDINT_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | struct stmt; /* forward declaration from "stmt.h" */ 30 | 31 | struct switch_case_map { 32 | struct switch_case *first_; /* first case in next_/prev_ chain */ 33 | struct switch_case *root_; /* root of red-black tree */ 34 | struct switch_case *default_; /* default case ; cannot exist in RB tree but does exist in chain.*/ 35 | }; 36 | 37 | struct switch_case { 38 | uint64_t case_value_; 39 | int is_red_ : 1; 40 | struct switch_case *left_, *right_; 41 | struct switch_case *next_, *prev_; 42 | 43 | struct stmt *case_stmt_; 44 | }; 45 | 46 | void switch_case_map_init(struct switch_case_map *scm); 47 | void switch_case_map_cleanup(struct switch_case_map *scm); 48 | 49 | /* Allocate and insert a new switch_case in the switch_case_map scm 50 | * NOTE: IF the case value already exists, then the *existing* switch_case is returned. 51 | * Caller should check that switch_case::case_stmt_ equals case_stmt. */ 52 | struct switch_case *switch_alloc_case(struct switch_case_map *scm, struct stmt *case_stmt, uint64_t case_value); 53 | struct switch_case *switch_alloc_default(struct switch_case_map *scm, struct stmt *default_stmt); 54 | 55 | void switch_free_case(struct switch_case_map *scm, uint64_t case_value); 56 | 57 | struct switch_case *switch_find_case(struct switch_case_map *scm, uint64_t case_value); 58 | 59 | #ifdef __cplusplus 60 | } /* extern "C" */ 61 | #endif 62 | 63 | #endif /* SWITCH_H */ 64 | -------------------------------------------------------------------------------- /examples/kc/src/symtab.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef SYMTAB_H 17 | #define SYMTAB_H 18 | 19 | #ifndef STDINT_H_INCLUDED 20 | #define STDINT_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | struct sym { 29 | uint64_t hash_value_; 30 | char *ident_; /* ident_ storage is allocated as part of sym, free()'ing the sym frees the ident_ with it. */ 31 | int is_red_ : 1; 32 | struct sym *left_, *right_; 33 | struct sym *next_, *prev_; 34 | }; 35 | 36 | struct symtab { 37 | struct sym *root_; 38 | 39 | /* All symbols in the table as a cyclic list in order of declaration, points 40 | * to the first sym declared */ 41 | struct sym *seq_; 42 | }; 43 | 44 | void st_init(struct symtab *st); 45 | 46 | /* Note that st_cleanup detaches all syms from the symtab, but does not clean up the individual 47 | * syms, as it does not own the link and does not have an awareness of what structure the sym 48 | * is embedded in. */ 49 | void st_cleanup(struct symtab *st); 50 | 51 | struct sym *st_find_or_insert(struct symtab *st, const char *value_key, int *s_is_new, size_t sym_size); 52 | struct sym *st_find(struct symtab *st, const char *value_key); 53 | 54 | int st_remove(struct symtab *st, struct sym *s); 55 | 56 | int st_check_sanity(struct symtab *st); 57 | 58 | #ifdef __cplusplus 59 | } /* extern "C" */ 60 | #endif 61 | 62 | #endif /* SYMTAB_H */ 63 | -------------------------------------------------------------------------------- /examples/tilly/directive_input_splitter.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | 17 | #ifndef STDLIB_H_INCLUDED 18 | #define STDLIB_H_INCLUDED 19 | #include 20 | #endif 21 | 22 | #ifndef STDINT_H_INCLUDED 23 | #define STDINT_H_INCLUDED 24 | #include 25 | #endif 26 | 27 | #ifndef VECTOR_INCLUDED 28 | #define VECTOR_INCLUDED 29 | #include 30 | #endif 31 | 32 | #ifndef DIRECTIVE_INPUT_SPLITTER_DEFS_H_INCLUDED 33 | #define DIRECTIVE_INPUT_SPLITTER_DEFS_H_INCLUDED 34 | #include "directive_input_splitter_defs.h" 35 | #endif 36 | 37 | #ifndef DIRECTIVE_INPUT_SPLITTER_H_INCLUDED 38 | #define DIRECTIVE_INPUT_SPLITTER_H_INCLUDED 39 | #include "directive_input_splitter.h" 40 | #endif 41 | 42 | #ifndef SITUS_H_INCLUDED 43 | #define SITUS_H_INCLUDED 44 | #include "situs.h" 45 | #endif 46 | 47 | %header% 48 | #ifndef STDINT_H_INCLUDED 49 | #define STDINT_H_INCLUDED 50 | #include /* uint8_t */ 51 | #endif 52 | 53 | %scanner% 54 | %prefix dis_ 55 | 56 | %common_class Situs 57 | %externc 58 | 59 | %params Situs &input_situs, std::vector &output, Situs &output_situs 60 | 61 | $: { 62 | // Move Situs from the input to the current match 63 | $.move_range(&input_situs, $endoffset - $offset, $text); 64 | } 65 | 66 | : [\ \t\v]* % .* (\r\n|\n)? { 67 | // A directive line 68 | output_situs.concat(&$); 69 | output.insert(output.end(), $text, $text + $len); 70 | return DIS_DIRECTIVE_LINE_AVAILABLE; 71 | } 72 | 73 | : .* (\r\n|\n)? { 74 | // Anything else; part of whatever the current section is. 75 | output_situs.concat(&$); 76 | output.insert(output.end(), $text, $text + $len); 77 | return DIS_SECTION_LINE_AVAILABLE; 78 | } 79 | -------------------------------------------------------------------------------- /examples/tilly/directive_input_splitter_defs.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef DIRECTIVE_INPUT_SPLITTER_DEFS_H 17 | #define DIRECTIVE_INPUT_SPLITTER_DEFS_H 18 | 19 | #ifndef SITUS_H_INCLUDED 20 | #define SITUS_H_INCLUDED 21 | #include "situs.h" 22 | #endif 23 | 24 | // returned by scanner if the current line is a directive line (starts with %) 25 | #define DIS_DIRECTIVE_LINE_AVAILABLE -1 26 | 27 | // returned by scanner if the current line is not a directive line (starts with something other than % or is empty.) 28 | #define DIS_SECTION_LINE_AVAILABLE -2 29 | 30 | #endif /* DIRECTIVE_INPUT_SPLITTER_DEFS_H */ 31 | -------------------------------------------------------------------------------- /examples/tilly/directives_defs.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef DIRECTIVES_DEFS_H 17 | #define DIRECTIVES_DEFS_H 18 | 19 | #ifndef SITUS_H_INCLUDED 20 | #define SITUS_H_INCLUDED 21 | #include "situs.h" 22 | #endif 23 | 24 | #define DIR_LINE_AVAILABLE -1 25 | #define DIR_TOGGLE_CODE_SECTION -2 26 | 27 | #endif /* DIRECTIVES_DEFS_H */ 28 | -------------------------------------------------------------------------------- /examples/tilly/line_continuation.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | 17 | #ifndef STDLIB_H_INCLUDED 18 | #define STDLIB_H_INCLUDED 19 | #include 20 | #endif 21 | 22 | #ifndef STDINT_H_INCLUDED 23 | #define STDINT_H_INCLUDED 24 | #include 25 | #endif 26 | 27 | #ifndef VECTOR_INCLUDED 28 | #define VECTOR_INCLUDED 29 | #include 30 | #endif 31 | 32 | #ifndef LINE_CONTINUATION_DEFS_H_INCLUDED 33 | #define LINE_CONTINUATION_DEFS_H_INCLUDED 34 | #include "line_continuation_defs.h" 35 | #endif 36 | 37 | #ifndef LINE_CONTINUATION_H_INCLUDED 38 | #define LINE_CONTINUATION_H_INCLUDED 39 | #include "line_continuation.h" // include this so we grab the extern "C" on declarations 40 | #endif 41 | 42 | #ifndef SITUS_H_INCLUDED 43 | #define SITUS_H_INCLUDED 44 | #include "situs.h" 45 | #endif 46 | 47 | %header% 48 | #ifndef STDINT_H_INCLUDED 49 | #define STDINT_H_INCLUDED 50 | #include /* uint8_t */ 51 | #endif 52 | 53 | %scanner% 54 | %prefix lc_ 55 | %externc 56 | 57 | %common_class Situs 58 | 59 | %params const char *filename, std::vector &output, Situs &output_situs 60 | 61 | $: { 62 | $.num_spans_ = 1; 63 | $.u_.one_.filename_ = filename; 64 | $.u_.one_.is_substitution_ = 0; 65 | $.u_.one_.num_bytes_ = $len; 66 | $.u_.one_.start_ = $offset; 67 | $.u_.one_.end_ = $endoffset; 68 | $.u_.one_.start_line_ = $line; 69 | $.u_.one_.start_col_ = $column; 70 | $.u_.one_.end_line_ = $endline; 71 | $.u_.one_.end_col_ = $endcolumn; 72 | } 73 | 74 | : \\\r\n|\\\n { 75 | // Line continuation - we remove these from the stream by taking no action; we 76 | // record this as a substitution for nothing. 77 | $.convert_to_substitution(0); 78 | output_situs.concat(&$); 79 | } 80 | 81 | : \r\n|\n { 82 | // Regular new line 83 | output_situs.concat(&$); 84 | output.insert(output.end(), $text, $text + $len); 85 | return LC_LINE_AVAILABLE; 86 | } 87 | 88 | : . { 89 | // Anything else. 90 | output_situs.concat(&$); 91 | output.insert(output.end(), $text, $text + $len); 92 | } 93 | -------------------------------------------------------------------------------- /examples/tilly/line_continuation_defs.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef LINE_CONTINUATION_DEFS_H 17 | #define LINE_CONTINUATION_DEFS_H 18 | 19 | #ifndef SITUS_H_INCLUDED 20 | #define SITUS_H_INCLUDED 21 | #include "situs.h" 22 | #endif 23 | 24 | #define LC_LINE_AVAILABLE -1 25 | 26 | #endif /* LINE_CONTINUATION_DEFS_H */ 27 | -------------------------------------------------------------------------------- /examples/tilly/multi_line_comments.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | 17 | #ifndef STDLIB_H_INCLUDED 18 | #define STDLIB_H_INCLUDED 19 | #include 20 | #endif 21 | 22 | #ifndef STDINT_H_INCLUDED 23 | #define STDINT_H_INCLUDED 24 | #include 25 | #endif 26 | 27 | #ifndef VECTOR_INCLUDED 28 | #define VECTOR_INCLUDED 29 | #include 30 | #endif 31 | 32 | #ifndef MULTI_LINE_COMMENTS_DEFS_H_INCLUDED 33 | #define MULTI_LINE_COMMENTS_DEFS_H_INCLUDED 34 | #include "multi_line_comments_defs.h" 35 | #endif 36 | 37 | #ifndef MULTI_LINE_COMMENTS_H_INCLUDED 38 | #define MULTI_LINE_COMMENTS_H_INCLUDED 39 | #include "multi_line_comments.h" 40 | #endif 41 | 42 | #ifndef LINE_CONTINUATION_H_INCLUDED 43 | #define LINE_CONTINUATION_H_INCLUDED 44 | #include "line_continuation.h" // include this so we grab the extern "C" on declarations 45 | #endif 46 | 47 | #ifndef SITUS_H_INCLUDED 48 | #define SITUS_H_INCLUDED 49 | #include "situs.h" 50 | #endif 51 | 52 | %header% 53 | #ifndef STDINT_H_INCLUDED 54 | #define STDINT_H_INCLUDED 55 | #include /* uint8_t */ 56 | #endif 57 | 58 | %scanner% 59 | %prefix mlc_ 60 | 61 | %common_class Situs 62 | 63 | %params Situs &input_situs, std::vector &output, Situs &output_situs 64 | 65 | $: { 66 | // Move Situs from the input to the current match 67 | $.move_range(&input_situs, $endoffset - $offset, $text); 68 | } 69 | 70 | : / /.* { 71 | // C++ comment up to, but not including the newline ('.' excludes newlines.) 72 | // The C++ comment is eaten whole - record this as a substitution for nothing - newline remains. 73 | $.convert_to_substitution(0); 74 | output_situs.concat(&$); 75 | } 76 | 77 | : /\*([^\*]|[\r\n]|(\*+([^\*/]|[\r\n])))*\*/ { 78 | // C-style comment, replace with a single space. 79 | $.convert_to_substitution(1); 80 | output.push_back(' '); 81 | output_situs.move_range(&$, 1, " "); 82 | } 83 | 84 | : L?"(\\.|[^"\\])*" { 85 | /* String literals should not have their contents examined for comments */ 86 | output_situs.concat(&$); 87 | output.insert(output.end(), $text, $text + $len); 88 | } 89 | 90 | : L?'(\\.|[^'\\])*' { 91 | /* Char literals should not have their contents examined for comments */ 92 | output_situs.concat(&$); 93 | output.insert(output.end(), $text, $text + $len); 94 | } 95 | 96 | : \r\n|\n { 97 | // Regular new line 98 | output_situs.concat(&$); 99 | output.insert(output.end(), $text, $text + $len); 100 | return MLC_LINE_AVAILABLE; 101 | } 102 | 103 | : . \Z { 104 | // Character before the end. 105 | output_situs.concat(&$); 106 | output.insert(output.end(), $text, $text + $len); 107 | return MLC_LINE_AVAILABLE; 108 | } 109 | : . { 110 | // Anything else. 111 | output_situs.concat(&$); 112 | output.insert(output.end(), $text, $text + $len); 113 | } 114 | 115 | -------------------------------------------------------------------------------- /examples/tilly/multi_line_comments_defs.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef MULTI_LINE_COMMENTS_DEFS_H 17 | #define MULTI_LINE_COMMENTS_DEFS_H 18 | 19 | #ifndef SITUS_H_INCLUDED 20 | #define SITUS_H_INCLUDED 21 | #include "situs.h" 22 | #endif 23 | 24 | #define MLC_LINE_AVAILABLE -1 25 | 26 | #endif /* MULTI_LINE_COMMENTS_DEFS_H */ -------------------------------------------------------------------------------- /examples/tilly/tiles_defs.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2023-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef TILES_DEFS_H 17 | #define TILES_DEFS_H 18 | 19 | #ifndef SITUS_H_INCLUDED 20 | #define SITUS_H_INCLUDED 21 | #include "situs.h" 22 | #endif 23 | 24 | // ... currently no definitions. 25 | 26 | #endif /* TILES_DEFS_H */ -------------------------------------------------------------------------------- /project/calc.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /project/calc.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /project/carburetta.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /project/inireader/inireader.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /project/inireader/inireader.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /project/kc.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | helpers 25 | 26 | 27 | helpers 28 | 29 | 30 | helpers 31 | 32 | 33 | 3rdparty\David M Gay - dtoa 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | {04b3a326-2adc-41d1-85f2-57569560c9a3} 74 | 75 | 76 | {a6d6cf33-c777-4855-9885-3ad5236d6143} 77 | 78 | 79 | {bac2ac35-0ca0-4ce8-8bca-050096d213e3} 80 | 81 | 82 | -------------------------------------------------------------------------------- /project/kc.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /project/template_scan.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /project/template_scan.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --notice C:\carburetta\NOTICE 5 | WindowsLocalDebugger 6 | 7 | 8 | --notice C:\carburetta\NOTICE 9 | WindowsLocalDebugger 10 | 11 | 12 | --notice C:\carburetta\NOTICE 13 | WindowsLocalDebugger 14 | 15 | 16 | --notice C:\carburetta\NOTICE 17 | WindowsLocalDebugger 18 | 19 | -------------------------------------------------------------------------------- /project/tester.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /project/tester.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /project/tilly.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Carburetta - Fused Scanner & Parser Generator 2 | 3 | Carburetta is a fused scanner & parser generator for C and C++. It aims to make parsing of smaller languages trivial and larger languages doable. 4 | 5 | Please note that this project is _not accepting pull requests_, both due to the intricacies of the code making isolated changes impractical, and the impracticality of determining contribution ownership. 6 | 7 | To access Carburetta's manual and learn more about the product, visit the website at [https://carburetta.com/](https://carburetta.com/). 8 | 9 | ## Getting Started 10 | 11 | ```c 12 | #include 13 | #include 14 | #include 15 | 16 | %scanner% 17 | %prefix calc_ 18 | 19 | : [\ \n]+; /* skip whitespace */ 20 | 21 | PLUS: \+; 22 | MINUS: \-; 23 | ASTERISK: \*; 24 | SLASH: /; 25 | TILDE: ~; 26 | BANG: !; 27 | PAR_OPEN: \(; 28 | PAR_CLOSE: \); 29 | INTEGER: [0-9]+ { 30 | $$ = atoi($text); 31 | } 32 | 33 | %token PLUS MINUS ASTERISK SLASH TILDE BANG PAR_OPEN PAR_CLOSE INTEGER 34 | %nt grammar expr term factor value 35 | 36 | 37 | %grammar% 38 | 39 | %type grammar expr term factor value: int 40 | 41 | %token_type int 42 | %constructor $$ = 0; 43 | %params int *final_result 44 | 45 | grammar: expr { printf("Outcome: %d\n", $0); *final_result = $0; } 46 | 47 | expr: term { $$ = $0; } 48 | expr: expr PLUS term { $$ = $0 + $2; } 49 | expr: expr MINUS term { $$ = $0 - $2; } 50 | 51 | term: factor { $$ = $0; } 52 | term: term ASTERISK factor { $$ = $0 * $2; } 53 | term: term SLASH factor { $$ = $0 / $2; } 54 | 55 | factor: value { $$ = $0; } 56 | factor: TILDE factor { $$ = ~$1; } 57 | factor: BANG factor { $$ = !$1; } 58 | factor: MINUS factor { $$ = -$1; } 59 | factor: PAR_OPEN expr PAR_CLOSE { $$ = $1; } 60 | 61 | value: INTEGER { $$ = $0; } 62 | 63 | %% 64 | 65 | int main(int argc, char **argv) { 66 | struct calc_stack stack; 67 | calc_stack_init(&stack); 68 | 69 | int final_result; 70 | static char s[300]; 71 | 72 | fprintf(stderr, "Enter an expression (-1 to terminate):\n"); 73 | 74 | do { 75 | if (!fgets(s, sizeof(s), stdin)) { 76 | break; 77 | } 78 | calc_stack_reset(&stack); 79 | calc_set_input(&stack, s, strlen(s), 1); 80 | calc_scan(&stack, &final_result); 81 | } while (final_result != -1); 82 | calc_stack_cleanup(&stack); 83 | 84 | return final_result; 85 | } 86 | 87 | ``` 88 | 89 | ## Usage 90 | 91 | ```shell 92 | $ carburetta inputfile.cbrt --c parser.c --h 93 | ``` 94 | 95 | Will read the input grammar in `inputfile.cbrt` and generate the C file `parser.c` containing the parser code, and a header file `parser.h` containing the declarations 96 | necessary for calling the parser from another source file. 97 | 98 | -------------------------------------------------------------------------------- /src/carburetta_context.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef CARBURETTA_CONTEXT_H 17 | #define CARBURETTA_CONTEXT_H 18 | 19 | #ifndef SYMBOL_H_INCLUDED 20 | #define SYMBOL_H_INCLUDED 21 | #include "symbol.h" 22 | #endif 23 | 24 | #ifndef MODE_H_INCLUDED 25 | #define MODE_H_INCLUDED 26 | #include "mode.h" 27 | #endif 28 | 29 | #ifndef TYPESTR_H_INCLUDED 30 | #define TYPESTR_H_INCLUDED 31 | #include "typestr.h" 32 | #endif 33 | 34 | #ifndef PRD_GRAM_H_INCLUDED 35 | #define PRD_GRAM_H_INCLUDED 36 | #include "prd_gram.h" 37 | #endif 38 | 39 | #ifndef SNIPPET_H_INCLUDED 40 | #define SNIPPET_H_INCLUDED 41 | #include "snippet.h" 42 | #endif 43 | 44 | #ifndef XLTS_H_INCLUDED 45 | #define XLTS_H_INCLUDED 46 | #include "xlts.h" 47 | #endif 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | struct conflict_resolution { 54 | struct conflict_resolution *next_; 55 | 56 | struct prd_production prefer_prod_; 57 | int prefer_prod_place_; 58 | struct prd_production over_prod_; 59 | int over_prod_place_; 60 | }; 61 | 62 | struct part { 63 | struct part *next_; 64 | size_t num_chars_; 65 | char *chars_; 66 | }; 67 | 68 | struct carburetta_context { 69 | struct snippet token_type_; 70 | struct snippet common_data_type_; 71 | struct symbol_table symtab_; 72 | struct mode_table modetab_; 73 | struct typestr_table tstab_; 74 | struct typestr *most_recent_typestr_; 75 | struct typestr *token_assigned_type_; 76 | struct typestr *common_data_assigned_type_; 77 | struct xlts prefix_; 78 | char *prefix_uppercase_; 79 | struct xlts token_prefix_; 80 | char *token_prefix_uppercase_; 81 | struct snippet params_snippet_; 82 | struct snippet visit_params_snippet_; 83 | struct snippet locals_snippet_; 84 | struct snippet on_finish_snippet_; 85 | struct snippet on_syntax_error_snippet_; 86 | struct snippet on_lexical_error_snippet_; 87 | struct snippet on_alloc_error_snippet_; 88 | struct snippet on_internal_error_snippet_; 89 | struct snippet on_next_token_snippet_; 90 | struct snippet on_scan_token_snippet_; 91 | struct snippet on_feed_me_snippet_; 92 | struct symbol *input_end_sym_; 93 | struct symbol *error_sym_; 94 | struct prd_production prefer_prod_; 95 | int prefer_prod_place_; 96 | struct prd_production over_prod_; 97 | int over_prod_place_; 98 | struct conflict_resolution *conflict_resolutions_; 99 | int have_typed_symbols_ :1; 100 | int have_cpp_classes_ :1; /* Have C++ classes as types, e.g. %class directive has been used */ 101 | int generate_externc_:1; /* Generate extern "C" { ... } around the generated code */ 102 | int generate_visit_func_:1; /* Generate a visit function (true if %visit or %visit-params is specified, false otherwise) */ 103 | struct xlts externc_option_; /* "%externc" or "%noexternc"; but only when this is specified, used to determine if generate_externc_ flag is implicit or explicit. */ 104 | char *h_output_filename_; 105 | char *c_output_filename_; 106 | char *include_guard_; 107 | struct part *prologue_; 108 | struct part *header_; 109 | struct part *epilogue_; 110 | int current_snippet_continuation_; 111 | int continuation_enabled_:1; 112 | int utf8_experimental_:1; 113 | int emit_line_directives_:1; 114 | }; 115 | 116 | void carburetta_context_init(struct carburetta_context *cc); 117 | void carburetta_context_cleanup(struct carburetta_context *cc); 118 | 119 | void conflict_resolution_init(struct conflict_resolution *cr); 120 | void conflict_resolution_cleanup(struct conflict_resolution *cr); 121 | 122 | struct part *parts_append(struct part **tailptr, size_t num_chars, char *chars); 123 | 124 | #ifdef __cplusplus 125 | } /* extern "C" */ 126 | #endif 127 | 128 | #endif /* CARBURETTA_CONTEXT_H */ 129 | -------------------------------------------------------------------------------- /src/chain.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef STDLIB_H_INCLUDED 17 | #define STDLIB_H_INCLUDED 18 | #include /* size_t, NULL */ 19 | #endif 20 | 21 | #ifndef CHAIN_H_INCLUDED 22 | #define CHAIN_H_INCLUDED 23 | #include "chain.h" 24 | #endif 25 | 26 | /* Returns the 'chain' pointer from a member offset and element pointer. 27 | * Because of the indirection, it is returned as an lvalue, eg. the 28 | * following code is legal: 29 | * CHAIN_GET_PTR_LVALUE(elm,member) = NULL; 30 | */ 31 | #define CHAIN_GET_PTR_LVALUE(element, member)\ 32 | (*(void**)(((char *)element)+member)) 33 | 34 | void *chain_first(void *chain, size_t member) { 35 | if (!chain) return NULL; 36 | return CHAIN_GET_PTR_LVALUE(chain, member); 37 | } 38 | 39 | void *chain_last(void *chain, size_t member) { 40 | (void)member; /* C4100: 'member' : unreferenced formal parameter */ 41 | return chain; 42 | } 43 | 44 | void *chain_pop(void **pchain, size_t member) { 45 | void *head; 46 | if (!*pchain) return NULL; 47 | head = CHAIN_GET_PTR_LVALUE(*pchain, member); 48 | if (head == *pchain) { 49 | /* first element is also the last, set to NULL, chain 50 | * is now empty. */ 51 | *pchain = NULL; 52 | return head; 53 | } 54 | /* Stitch tail's successor to point to successor of previous head, 55 | * then make head a little chain of itself. */ 56 | CHAIN_GET_PTR_LVALUE(*pchain, member) = CHAIN_GET_PTR_LVALUE(head, member); 57 | CHAIN_GET_PTR_LVALUE(head, member) = head; 58 | return head; 59 | } 60 | 61 | void *chain_next(void *chain, size_t member, void *prev) { 62 | if (!prev) return chain_first(chain, member); 63 | if (prev == chain) return NULL; 64 | return CHAIN_GET_PTR_LVALUE(prev, member); 65 | } 66 | 67 | void *chain_append(void *front, void *back, size_t member) { 68 | void *front_head, *front_tail, *back_head, *back_tail; 69 | if (!front) return back; 70 | if (!back) return front; 71 | front_head = chain_first(front, member); 72 | front_tail = chain_last(front, member); 73 | back_head = chain_first(back, member); 74 | back_tail = chain_last(back, member); 75 | CHAIN_GET_PTR_LVALUE(back_tail, member) = front_head; 76 | CHAIN_GET_PTR_LVALUE(front_tail, member) = back_head; 77 | return back_tail; /* next(back_tail) is front_head, eg. it is the proper tail ptr. */ 78 | } 79 | 80 | size_t chain_length(void *chain, size_t member) { 81 | void *elm; 82 | size_t nr_elems = 0; 83 | for (elm = chain_first(chain, member); 84 | elm; 85 | elm = chain_next(chain, member, elm)) { 86 | nr_elems++; 87 | } 88 | return nr_elems; 89 | } 90 | 91 | void chain_reverse(void **pchain, size_t member) { 92 | void *new_chain = NULL; 93 | void *elm; 94 | /* Akward for() construct to avoid C4706: assignment within conditional expression */ 95 | for (elm = chain_pop(pchain, member); 96 | elm; 97 | elm = chain_pop(pchain, member)) { 98 | new_chain = chain_append(elm, new_chain, member); 99 | } 100 | *pchain = new_chain; 101 | } 102 | 103 | void chain_init(void *element, size_t member) { 104 | CHAIN_GET_PTR_LVALUE(element, member) = element; 105 | } 106 | -------------------------------------------------------------------------------- /src/decomment.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef DECOMMENT_H 17 | #define DECOMMENT_H 18 | 19 | #ifndef XLTS_H_INCLUDED 20 | #define XLTS_H_INCLUDED 21 | #include "xlts.h" 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* Removes C-Style and C++ Style comments from an xlts string, useful when the tokenizer that next parses the string does not support comments. */ 29 | int dct_init(void); 30 | void dct_cleanup(void); 31 | 32 | int dct_decomment(struct xlts *val); 33 | 34 | #ifdef __cplusplus 35 | } /* extern "C" */ 36 | #endif 37 | 38 | #endif /* DECOMMENT_H */ 39 | -------------------------------------------------------------------------------- /src/dfa.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef DFA_H 17 | #define DFA_H 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif /* __cplusplus */ 22 | 23 | #ifndef STDDEF_H_INCLUDED 24 | #define STDDEF_H_INCLUDED 25 | #include /* size_t */ 26 | #endif 27 | 28 | #ifndef NFA_H_INCLUDED 29 | #define NFA_H_INCLUDED 30 | #include "nfa.h" 31 | #endif 32 | 33 | struct dfa_node { 34 | /* Unique number of the DFA state, this becomes the row index for a 35 | * scanning table; assigned from dfa_context_t::next_dfa_num when the 36 | * DFA is "recorded" (dfa_record_node() in the C file) */ 37 | size_t num; 38 | 39 | /* Next in chain of all distinct DFA nodes */ 40 | struct dfa_node *next_dfa; 41 | 42 | /* Array of all moves, indexed by unsigned input character, NULL when 43 | * the character is invalid. */ 44 | struct dfa_node *moves[256]; 45 | 46 | /* Bitmap of all NFA indices, dynamically allocated to be of sufficient 47 | * size to index all NFA's (eg. (num_nfa_nodes + 63) / 64. */ 48 | uint64_t nfa_map[1]; 49 | }; 50 | 51 | struct dfa { 52 | /* All DFA nodes */ 53 | struct dfa_node *first_dfa; 54 | 55 | /* Next DFA number to assign in dfa_node::num */ 56 | size_t next_dfa_num; 57 | 58 | /* Total number of NFA nodes, this determines the 59 | * size of the allocation for DFA nodes due to 60 | * the nfa_map member in dfa_node*/ 61 | size_t num_nfa_nodes; 62 | }; 63 | 64 | void dfa_init(struct dfa *dfa); 65 | void dfa_cleanup(struct dfa *dfa); 66 | 67 | int dfa_node_has_nfa(struct dfa_node *dfa_node, size_t nfa_node_index); 68 | 69 | /* Returns the DFA node corresponding to the NFA start node */ 70 | struct dfa_node *dfa_make(struct dfa *dfa, struct nfa *nfa, size_t nfa_start); 71 | 72 | void dfa_dump_node(struct dfa *odfa, struct dfa_node *d); 73 | 74 | 75 | #ifdef __cplusplus 76 | } /* extern "C" */ 77 | #endif 78 | 79 | #endif /* DFA_H */ 80 | -------------------------------------------------------------------------------- /src/emit_c.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef EMIT_C_H 17 | #define EMIT_C_H 18 | 19 | #ifndef STDIO_H_INCLUDED 20 | #define STDIO_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | #ifndef SCANNER_H_INCLUDED 25 | #define SCANNER_H_INCLUDED 26 | #include "scanner.h" 27 | #endif 28 | 29 | #ifndef REX_H_INCLUDED 30 | #define REX_H_INCLUDED 31 | #include "rex.h" 32 | #endif 33 | 34 | #ifndef LALR_H_INCLUDED 35 | #define LALR_H_INCLUDED 36 | #include "lalr.h" 37 | #endif 38 | 39 | #ifndef REPORT_ERROR_H_INCLUDED 40 | #define REPORT_ERROR_H_INCLUDED 41 | #include "report_error.h" 42 | #endif 43 | 44 | #ifndef CARBURETTA_CONTEXT_H_INCLUDED 45 | #define CARBURETTA_CONTEXT_H_INCLUDED 46 | #include "carburetta_context.h" 47 | #endif 48 | 49 | #ifndef INDENTED_PRINTER_H_INCLUDED 50 | #define INDENTED_PRINTER_H_INCLUDED 51 | #include "indented_printer.h" 52 | #endif 53 | 54 | #ifdef __cplusplus 55 | extern "C" { 56 | #endif 57 | 58 | const char *cc_prefix(struct carburetta_context *cc); 59 | const char *cc_PREFIX(struct carburetta_context *cc); 60 | 61 | void emit_c_file(struct indented_printer *ip, struct carburetta_context *cc, struct prd_grammar *prdg, struct rex_scanner *rex, struct lr_generator *lalr); 62 | void emit_h_file(struct indented_printer *ip, struct carburetta_context *cc, struct prd_grammar *prdg); 63 | 64 | #ifdef __cplusplus 65 | } /* extern "C" */ 66 | #endif 67 | 68 | #endif /* EMIT_C_H */ 69 | -------------------------------------------------------------------------------- /src/grammar_table.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef GRAMMAR_TABLE_H 17 | #define GRAMMAR_TABLE_H 18 | 19 | #ifndef STDDEF_H_INCLUDED 20 | #define STDDEF_H_INCLUDED 21 | #include /* size_t */ 22 | #endif 23 | 24 | #ifndef LALR_H_INCLUDED 25 | #define LALR_H_INCLUDED 26 | #include "lalr.h" 27 | #endif 28 | 29 | #ifndef PRD_GRAM_H_INCLUDED 30 | #define PRD_GRAM_H_INCLUDED 31 | #include "prd_gram.h" 32 | #endif 33 | 34 | #ifndef SYMBOL_H_INCLUDED 35 | #define SYMBOL_H_INCLUDED 36 | #include "symbol.h" 37 | #endif 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | #define GT_OVERFLOW 1 44 | #define GT_NOMEM 2 45 | #define GT_NOT_LR_GRAMMAR 3 46 | #define GT_AMBIGUOUS_GRAMMAR 4 47 | #define GT_CONFLICTS 5 48 | #define GT_INTERNAL_ERROR 6 49 | 50 | struct grammar_table { 51 | size_t num_ordinals_; 52 | size_t num_ordinals_allocated_; 53 | int *ordinals_; 54 | }; 55 | 56 | void gt_grammar_table_init(struct grammar_table *gt); 57 | void gt_grammar_table_cleanup(struct grammar_table *gt); 58 | 59 | int gt_emit(struct grammar_table *gt, int ordinal); 60 | 61 | int gt_transcribe_grammar(struct grammar_table *gt, size_t num_productions, struct prd_production *productions, int end_of_production_sym, int end_of_grammar_sym); 62 | void gt_debug_grammar(struct grammar_table *gt, size_t num_productions, struct prd_production *productions, int end_of_production_sym, int end_of_grammar_sym); 63 | int gt_generate_lalr(struct grammar_table *gt, struct lr_generator *lalr, int end_of_production_sym, int end_of_grammar_sym, int end_of_file_sym, int synthetic_s_sym); 64 | 65 | #ifdef __cplusplus 66 | } /* extern "C" */ 67 | #endif 68 | 69 | #endif /* GRAMMAR_TABLE_H */ 70 | -------------------------------------------------------------------------------- /src/indented_printer.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef INDENTED_PRINTER_H 17 | #define INDENTED_PRINTER_H 18 | 19 | #ifndef STDIO_H_INCLUDED 20 | #define STDIO_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | #ifndef STDARG_H_INCLUDED 25 | #define STDARG_H_INCLUDED 26 | #include 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | enum ip_retained_output_bucket_type { 34 | IPROBT_BUFFER, 35 | IPROBT_LINE_NUM_PLUS_1 /* used for #line directives as placeholder for the next line number, emitted when we don't yet know that number */ 36 | }; 37 | 38 | struct ip_retained_output_bucket { 39 | enum ip_retained_output_bucket_type kind_; 40 | /* Size of struct allocation includes data in buf_ with null terminator (eg. buf_size_ + 1) */ 41 | struct ip_retained_output_bucket *next_; 42 | size_t buf_size_; 43 | char buf_[1]; 44 | }; 45 | 46 | struct indented_printer { 47 | FILE *outfp_; 48 | const char *filename_; 49 | int indentation_; 50 | int indent_size_; 51 | int had_error_:1; 52 | int at_start_of_line_:1; 53 | int retain_output_:1; 54 | int retained_line_num_; 55 | int current_line_num_; 56 | struct ip_retained_output_bucket *retained_output_; /* tail ptr */ 57 | }; 58 | 59 | void ip_init(struct indented_printer *ip, FILE *outfp, const char *filename); 60 | void ip_cleanup(struct indented_printer *ip); 61 | void ip_write_no_indent(struct indented_printer *ip, const char *s, size_t len); 62 | void ip_write_next_line_num(struct indented_printer *ip); 63 | void ip_puts_no_indent(struct indented_printer *ip, const char *s); 64 | void ip_puts(struct indented_printer *ip, const char *s); 65 | void ip_force_indent_print(struct indented_printer *ip); 66 | void ip_vprintf(struct indented_printer *ip, const char *format, va_list args); 67 | void ip_vprintf_no_indent(struct indented_printer *ip, const char *format, va_list args); 68 | void ip_printf(struct indented_printer *ip, const char *format, ...); 69 | void ip_printf_no_indent(struct indented_printer *ip, const char *format, ...); 70 | 71 | void ip_free_retained_output_bucket_chain(struct ip_retained_output_bucket *robc); 72 | void ip_write_retained_output_bucket_chain(struct indented_printer *ip, struct ip_retained_output_bucket *robc); 73 | void ip_set_retained_output(struct indented_printer *ip, int enable); 74 | struct ip_retained_output_bucket *ip_extract_retained_output(struct indented_printer *ip); 75 | 76 | #ifdef __cplusplus 77 | } /* extern "C" */ 78 | #endif 79 | 80 | #endif /* INDENTED_PRINTER_H */ 81 | -------------------------------------------------------------------------------- /src/line_assembly.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef LINE_ASSEMBLY_H 17 | #define LINE_ASSEMBLY_H 18 | 19 | /* Line assembly, assembles lines of input. 20 | * Lines are sequences of input that end with either a newline, or the end of input. 21 | * Lines may be extended by using a line-continuation (a backslash followed by a newline, or a backslash followed by a 22 | * carriage return and a newline.) 23 | * Lines may also be extended using a C-style multi-line comment such as the one you're reading. 24 | * These two may be combined, eg. the opening / and * may be encoded as "/\\\r\n*" and this should 25 | * still work. 26 | * Downstream from line assembly we still need to generate accurate line and column numbers; so these need to be preserved. 27 | * Downstream parsing should proceed as if the line-continuations were never part of the input and as if the C-style 28 | * comments were left untouched. 29 | * Downstream from line assembly, when we generate segments of code, we need to reproduce the line-continuations and 30 | * comments as they appeared in the original input. So while the line-continuations and multi-line comments affect the 31 | * input processing as if they've been removed from the input, on the code generating output, they must re-appear. They 32 | * must therefore be removed and kept at the same time. 33 | * Line assembly is surprisingly complicated. */ 34 | 35 | #ifndef STDDEF_H_INCLUDED 36 | #define STDDEF_H_INCLUDED 37 | #include /* size_t */ 38 | #endif 39 | 40 | #ifndef TOKENIZER_H_INCLUDED 41 | #define TOKENIZER_H_INCLUDED 42 | #include "tokenizer.h" 43 | #endif 44 | 45 | #ifndef XLTS_H_INCLUDED 46 | #define XLTS_H_INCLUDED 47 | #include "xlts.h" 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif 53 | 54 | #define LAS_END_OF_INPUT 0 55 | #define LAS_MATCH 1 56 | #define LAS_INTERNAL_ERROR 3 57 | #define LAS_FEED_ME 4 58 | 59 | struct las_line_assembly { 60 | /* Line continuation translation phase */ 61 | struct tkr_tokenizer lc_tkr_; 62 | 63 | int lc_clear_buffers_on_entry_ : 1, 64 | lc_last_line_emitted_ : 1, 65 | mlc_clear_buffers_on_entry_ : 1, 66 | mlc_last_line_emitted_ : 1, 67 | las_input_reentry_from_match_ : 1, 68 | mlc_has_final_input_ : 1; 69 | 70 | size_t mlc_cumulative_line_size_; 71 | 72 | struct xlts lc_buf_; 73 | 74 | /* Multi-line comment translation phase */ 75 | struct tkr_tokenizer mlc_tkr_; 76 | 77 | struct xlts mlc_buf_; 78 | 79 | struct xlts_clamp mlc_buf_early_termination_undo_; 80 | }; 81 | 82 | int las_init(void); 83 | void las_cleanup(void); 84 | 85 | void las_init_line_assembly(struct las_line_assembly *las); 86 | void las_cleanup_line_assembly(struct las_line_assembly *las); 87 | void las_set_filename(struct las_line_assembly *las, const char *filename); 88 | int las_input(struct las_line_assembly *las, const char *input, size_t input_size, int is_final_input); 89 | 90 | 91 | #ifdef __cplusplus 92 | } /* extern "C" */ 93 | #endif 94 | 95 | #endif /* LINE_ASSEMBLY_H */ 96 | -------------------------------------------------------------------------------- /src/line_defs.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef STDIO_H_INCLUDED 17 | #define STDIO_H_INCLUDED 18 | #include 19 | #endif 20 | 21 | #ifndef STDLIB_H_INCLUDED 22 | #define STDLIB_H_INCLUDED 23 | #include 24 | #endif 25 | 26 | #ifndef STRING_H_INCLUDED 27 | #define STRING_H_INCLUDED 28 | #include 29 | #endif 30 | 31 | #ifndef SCANNER_H_INCLUDED 32 | #define SCANNER_H_INCLUDED 33 | #include "scanner.h" 34 | #endif 35 | 36 | #ifndef TOKENIZER_H_INCLUDED 37 | #define TOKENIZER_H_INCLUDED 38 | #include "tokenizer.h" 39 | #endif 40 | 41 | #ifndef LINE_DEFS_H_INCLUDED 42 | #define LINE_DEFS_H_INCLUDED 43 | #include "line_defs.h" 44 | #endif 45 | 46 | #if __GNUC__ 47 | #pragma GCC diagnostic push 48 | #pragma GCC diagnostic ignored "-Wmissing-braces" 49 | #endif 50 | 51 | static const struct sc_scan_rule g_scanner_rules_[] = { 52 | #define xx(regex, line_type) { regex, line_type, line_type }, 53 | #define xz(line_type) 54 | ENUM_LINE_DEFS 55 | #undef xz 56 | #undef xx 57 | }; 58 | 59 | #if __GNUC__ 60 | #pragma GCC diagnostic pop 61 | #endif 62 | 63 | static struct sc_scanner g_ldl_scanner_; 64 | 65 | const char *ld_line_type_to_str(ld_line_type_t ldlt) { 66 | #define xx(regex, type_of_line) case type_of_line: return #type_of_line; 67 | #define xz(type_of_line) case type_of_line: return #type_of_line; 68 | switch (ldlt) { 69 | ENUM_LINE_DEFS 70 | } 71 | #undef xx 72 | #undef xz 73 | return "?"; 74 | } 75 | 76 | 77 | int ldl_init(void) { 78 | sc_scanner_init(&g_ldl_scanner_); 79 | int r; 80 | r = sc_scanner_compile(&g_ldl_scanner_, LD_UNKNOWN, sizeof(g_scanner_rules_) / sizeof(*g_scanner_rules_), g_scanner_rules_); 81 | return r; 82 | } 83 | 84 | void ldl_cleanup(void) { 85 | sc_scanner_cleanup(&g_ldl_scanner_); 86 | } 87 | 88 | void ldl_init_tokenizer(struct tkr_tokenizer *tkr) { 89 | tkr_tokenizer_init(tkr, &g_ldl_scanner_); 90 | } 91 | -------------------------------------------------------------------------------- /src/line_defs.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef LINE_DEFS_H 17 | #define LINE_DEFS_H 18 | 19 | #ifndef TOKENIZER_H_INCLUDED 20 | #define TOKENIZER_H_INCLUDED 21 | #include "tokenizer.h" 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | #define ENUM_LINE_DEFS \ 29 | xz(LD_UNKNOWN) \ 30 | xx("[ \\x9\\xb\\xc\\xd]*#.*\\n?", LD_C_PREPROCESSOR) \ 31 | xx("[ \\x9\\xb\\xc\\xd]*%scanner%[ \\x9\\xb\\xc\\xd]*\\n?", LD_CARBURETTA_SCANNER_SECTION_DELIMETER) \ 32 | xx("[ \\x9\\xb\\xc\\xd]*%grammar%[ \\x9\\xb\\xc\\xd]*\\n?", LD_CARBURETTA_GRAMMAR_SECTION_DELIMETER) \ 33 | xx("[ \\x9\\xb\\xc\\xd]*%header%[ \\x9\\xb\\xc\\xd]*\\n?", LD_CARBURETTA_HEADER_SECTION_DELIMETER) \ 34 | xx("[ \\x9\\xb\\xc\\xd]*%%[ \\x9\\xb\\xc\\xd]*\\n?", LD_CARBURETTA_SECTION_DELIMITER) \ 35 | xx("[ \\x9\\xb\\xc\\xd]*%.*\\n?", LD_CARBURETTA_DIRECTIVE) \ 36 | xx(".*\\n?", LD_REGULAR) 37 | 38 | typedef enum ld_line_type { 39 | #define xx(regex, type_of_line) type_of_line, 40 | #define xz(type_of_line) type_of_line, 41 | ENUM_LINE_DEFS 42 | #undef xx 43 | #undef xz 44 | } ld_line_type_t; 45 | 46 | int ldl_init(void); 47 | void ldl_cleanup(void); 48 | 49 | const char *ld_line_type_to_str(ld_line_type_t ldlt); 50 | 51 | void ldl_init_tokenizer(struct tkr_tokenizer *tkr); 52 | 53 | #ifdef __cplusplus 54 | } /* extern "C" */ 55 | #endif 56 | 57 | #endif /* LINE_DEFS_H */ 58 | -------------------------------------------------------------------------------- /src/mode.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef MODE_H 17 | #define MODE_H 18 | 19 | #ifndef XLTS_H_INCLUDED 20 | #define XLTS_H_INCLUDED 21 | #include "xlts.h" 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | #define MODE_TABLE_SIZE 31 29 | 30 | struct rex_mode; 31 | 32 | struct mode { 33 | /* Name and source location of definition */ 34 | struct xlts def_; 35 | 36 | /* Next in mode_table::modes_ */ 37 | struct mode *next_; 38 | 39 | /* Next in hash table */ 40 | struct mode *hash_chain_; 41 | 42 | /* Regular expression scantable builder's equivalent mode 43 | * (Not owned by struct mode) */ 44 | struct rex_mode *rex_mode_; 45 | }; 46 | 47 | struct mode_table { 48 | struct mode *mode_table_[MODE_TABLE_SIZE]; 49 | struct mode *modes_; 50 | }; 51 | 52 | void mode_table_init(struct mode_table *mt); 53 | void mode_table_cleanup(struct mode_table *mt); 54 | void mode_init(struct mode *m); 55 | void mode_cleanup(struct mode *m); 56 | 57 | struct mode *mode_find_or_add(struct mode_table *mt, struct xlts *id, int *is_new); 58 | struct mode *mode_find(struct mode_table *mt, const char *id); 59 | 60 | #ifdef __cplusplus 61 | } /* extern "C" */ 62 | #endif 63 | 64 | #endif /* MODE_H */ 65 | -------------------------------------------------------------------------------- /src/mul.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef STDINT_H_INCLUDED 17 | #define STDINT_H_INCLUDED 18 | #include 19 | #endif 20 | 21 | #ifndef MUL_H_INCLUDED 22 | #define MUL_H_INCLUDED 23 | #include "mul.h" 24 | #endif 25 | 26 | int multiply_uint64(uint64_t a, uint64_t b, uint64_t *rhi, uint64_t *rlo) { 27 | /* Multiplication: 28 | * xy = z2 b^2 + z1 b + z0 29 | * where: 30 | * z2 = x1y1 31 | * z1 = x1y0 + x0y1 32 | * z0 = x0y0 33 | * and b is base 2^32 */ 34 | uint32_t x0 = a & 0xFFFFFFFF; 35 | uint32_t x1 = (a >> 32) & 0xFFFFFFFF; 36 | uint32_t y0 = b & 0xFFFFFFFF; 37 | uint32_t y1 = (b >> 32) & 0xFFFFFFFF; 38 | 39 | uint64_t z2 = ((uint64_t)x1) * ((uint64_t)y1); 40 | uint64_t z0 = ((uint64_t)x0) * ((uint64_t)y0); 41 | uint64_t x1y0 = ((uint64_t)x1) * ((uint64_t)y0); 42 | uint64_t x0y1 = ((uint64_t)x0) * ((uint64_t)y1); 43 | uint64_t z1 = x1y0 + x0y1; 44 | if (z1 < x1y0) { 45 | /* Carry overflow from z1; add in to z2, note also that z2 46 | * is at most 0xFFFFFFFE00000001 and so consequently would 47 | * hereby become 0xFFFFFFFF00000001 in the worst case (we 48 | * therefore don't need to check for overflow) */ 49 | z2 += ((uint64_t)1) << 32; 50 | } 51 | uint64_t result0; 52 | uint64_t result1; 53 | result0 = z0 + (z1 << 32); 54 | if (result0 < z0) { 55 | /* Overflow from z0 + loword(z1) into upper word of result */ 56 | z2++; 57 | } 58 | result1 = (z1 >> 32) + z2; 59 | 60 | if (rlo) { 61 | *rlo = result0; 62 | } 63 | if (rhi) { 64 | /* note: can skip z2 if not interested in rhi */ 65 | *rhi = result1; 66 | } 67 | 68 | return !!result1; 69 | } 70 | 71 | int multiply_size_t(size_t a, size_t b, size_t *rhi, size_t *rlo) { 72 | /* Rely on compiler to optimize out this constant branch */ 73 | if (sizeof(size_t) == 4) { 74 | /* size_t is 32 bits */ 75 | uint64_t ab = ((uint64_t)a) * ((uint64_t)b); 76 | if (rlo) *rlo = (size_t)ab; 77 | size_t hi = (size_t)(ab >> 32); 78 | if (rhi) *rhi = hi; 79 | return !!hi; 80 | } 81 | else { 82 | /* size_t is 64 bits */ 83 | return multiply_uint64(a, b, (uint64_t *)rhi, (uint64_t *)rlo); 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /src/mul.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef MUL_H 17 | #define MUL_H 18 | 19 | #ifndef STDDEF_H_INCLUDED 20 | #define STDDEF_H_INCLUDED 21 | #include /* size_t */ 22 | #endif 23 | 24 | #ifndef STDINT_H_INCLUDED 25 | #define STDINT_H_INCLUDED 26 | #include /* uint64_t */ 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | int multiply_uint64(uint64_t a, uint64_t b, uint64_t *rhi, uint64_t *rlo); 34 | int multiply_size_t(size_t a, size_t b, size_t *rhi, size_t *rlo); 35 | 36 | #ifdef __cplusplus 37 | } /* extern "C" */ 38 | #endif 39 | 40 | #endif /* MUL_H */ 41 | -------------------------------------------------------------------------------- /src/nfa.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef NFA_H 17 | #define NFA_H 18 | 19 | #ifndef STDDEF_H_INCLUDED 20 | #define STDDEF_H_INCLUDED 21 | #include /* size_t */ 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif /* __cplusplus */ 27 | 28 | struct nfa_trans { 29 | size_t node; 30 | struct nfa_trans *next_trans; 31 | }; 32 | 33 | struct nfa_node { 34 | struct nfa_trans *empty_move; 35 | struct nfa_trans *moves[256]; 36 | }; 37 | 38 | struct nfa { 39 | /* All NFA nodes */ 40 | size_t num_nfa_nodes, num_nfa_nodes_allocated; 41 | struct nfa_node *nfa_nodes; 42 | 43 | /* If free_nfa is not ~0, it points to an NFA node 44 | * that is free and will be returned first in 45 | * allocation prior to expanding the array. This helps 46 | * reduce the size of the array as we frequently need 47 | * to temporarily let go of an NFA node when stitching 48 | * NFA strings together. */ 49 | size_t free_nfa; 50 | 51 | /* Indices of the NFA nodes where the NFA should start and stop */ 52 | size_t start_nfa, stop_nfa; 53 | }; 54 | 55 | void nfa_init(struct nfa *nfa); 56 | void nfa_cleanup(struct nfa *nfa); 57 | int nfa_parse_regexp(struct nfa *nfa, const char *regexp); 58 | 59 | /* Copies the NFA in src in dst and merges the two NFAs such that 60 | * the start of dst also includes the start of src. The end of dst 61 | * is retained, the end of the src NFA as a clone inside dst is 62 | * stored in new_src_end_node. 63 | * If dst is an empty NFA, this operation duplicates src into dst 64 | * and instead overwrites dst->start_nfa and dst->stop_nfa with the 65 | * now only NFA in dst. */ 66 | int nfa_merge_nfas(struct nfa *dst, struct nfa *src, size_t *new_src_end_node); 67 | 68 | #ifdef __cplusplus 69 | } /* extern "C" */ 70 | #endif 71 | 72 | #endif /* NFA_H */ 73 | -------------------------------------------------------------------------------- /src/parse_input.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef PARSE_INPUT_H 17 | #define PARSE_INPUT_H 18 | 19 | #ifndef STDIO_H_INCLUDED 20 | #define STDIO_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | int pi_parse_input(FILE *fp, const char *input_filename, struct carburetta_context *cc, struct prd_grammar *prdg); 29 | 30 | 31 | #ifdef __cplusplus 32 | } /* extern "C" */ 33 | #endif 34 | 35 | #endif /* PARSE_INPUT_H */ 36 | -------------------------------------------------------------------------------- /src/prd_grammar.h: -------------------------------------------------------------------------------- 1 | #ifndef CARB_PRD_PRD_GRAMMAR_H_INCLUDED 2 | #define CARB_PRD_PRD_GRAMMAR_H_INCLUDED 3 | 4 | #include /* size_t */ 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define _PRD_FINISH 0 11 | #define _PRD_MATCH 1 12 | #define _PRD_OVERFLOW 2 13 | #define _PRD_NO_MEMORY 3 14 | #define _PRD_FEED_ME 4 15 | #define _PRD_END_OF_INPUT 5 16 | #define _PRD_SYNTAX_ERROR 6 17 | #define _PRD_LEXICAL_ERROR 7 18 | #define _PRD_INTERNAL_ERROR 8 19 | 20 | #define PRD_IDENT 3 21 | #define PRD_COLON 4 22 | #define PRD_EQUALS 5 23 | #define PRD_SEMICOLON 6 24 | #define PRD_TOKEN 7 25 | #define PRD_PAR_OPEN 8 26 | #define PRD_PAR_CLOSE 9 27 | #define PRD_CUBRACE_OPEN 10 28 | #define PRD_CUBRACE_CLOSE 11 29 | #define PRD_DOLLAR 12 30 | #define PRD_ERROR 13 31 | #define PRD_INPUT_END 14 32 | 33 | #define PRD_GRAMMAR 15 34 | #define PRD_RULE 16 35 | #define PRD_PRODUCTION 17 36 | #define PRD_ACTION_SEQUENCE 18 37 | #define PRD_STMT_ACTION 19 38 | #define PRD_START_C_TOKENIZER 20 39 | #define PRD_END_C_TOKENIZER 21 40 | #define PRD_ACCEPT_WHITESPACE 22 41 | #define PRD_COMMON_ACTION 23 42 | 43 | 44 | struct prd_stack { 45 | int error_recovery_:1; 46 | int pending_reset_:1; 47 | int discard_remaining_actions_:1; 48 | int slot_1_has_sym_data_:1; 49 | int slot_1_has_common_data_:1; 50 | int top_of_stack_has_sym_data_:1; 51 | int top_of_stack_has_common_data_:1; 52 | int newbuf_pos_has_common_data_:1; 53 | int newbuf_pos_has_sym_data_:1; 54 | int stack_newbuf_pos_has_common_data_:1; 55 | int stack_newbuf_pos_has_sym_data_:1; 56 | int action_preservation_; 57 | int current_err_action_; 58 | int slot_1_sym_; 59 | int continue_at_; 60 | int mute_error_turns_; 61 | size_t pos_, num_stack_allocated_; 62 | struct prd_sym_data *stack_; 63 | struct prd_sym_data *sym_data_; 64 | struct prd_sym_data *new_buf_; 65 | size_t new_buf_num_allocated_; 66 | size_t new_buf_sym_partial_pos_; 67 | size_t current_production_length_; 68 | int current_production_nonterminal_; 69 | size_t sym_idx_; 70 | }; 71 | 72 | void prd_stack_init(struct prd_stack *stack); 73 | void prd_stack_cleanup(struct prd_stack *stack); 74 | int prd_stack_reset(struct prd_stack *stack); 75 | int prd_stack_can_recover(struct prd_stack *stack); 76 | int prd_stack_accepts(struct prd_stack *stack, int sym); 77 | int prd_parse(struct prd_stack *stack, int sym, struct prd_grammar *g, struct tkr_tokenizer *tkr, struct symbol_table *st); 78 | 79 | #ifdef __cplusplus 80 | } /* extern "C" */ 81 | #endif 82 | 83 | #endif /* CARB_PRD_PRD_GRAMMAR_H_INCLUDED */ 84 | -------------------------------------------------------------------------------- /src/regex_grammar.h: -------------------------------------------------------------------------------- 1 | #ifndef CARB_RXG_REGEX_GRAMMAR_H_INCLUDED 2 | #define CARB_RXG_REGEX_GRAMMAR_H_INCLUDED 3 | 4 | #include /* size_t */ 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define _RXG_FINISH 0 11 | #define _RXG_MATCH 1 12 | #define _RXG_OVERFLOW 2 13 | #define _RXG_NO_MEMORY 3 14 | #define _RXG_FEED_ME 4 15 | #define _RXG_END_OF_INPUT 5 16 | #define _RXG_SYNTAX_ERROR 6 17 | #define _RXG_LEXICAL_ERROR 7 18 | #define _RXG_INTERNAL_ERROR 8 19 | 20 | #define RXG_CHAR 3 21 | #define RXG_IDENT 4 22 | #define RXG_PAR_OPEN 5 23 | #define RXG_PAR_CLOSE 6 24 | #define RXG_CUR_OPEN 7 25 | #define RXG_CUR_CLOSE 8 26 | #define RXG_COLON 9 27 | #define RXG_SEMICOLON 10 28 | #define RXG_SQ_OPEN 11 29 | #define RXG_SQ_CLOSE 12 30 | #define RXG_DOT 13 31 | #define RXG_DOLLAR 14 32 | #define RXG_CARET 15 33 | #define RXG_DASH 16 34 | #define RXG_BAR 17 35 | #define RXG_ASTERISK 18 36 | #define RXG_PLUS 19 37 | #define RXG_QUESTION_MARK 20 38 | #define RXG_TOKEN 21 39 | #define RXG_WHITESPACE 22 40 | #define RXG_START_OF_INPUT_ESC 23 41 | #define RXG_END_OF_INPUT_ESC 24 42 | #define RXG_LESS_THAN 25 43 | #define RXG_GREATER_THAN 26 44 | #define RXG_COMMA 27 45 | #define RXG_CATEGORY 28 46 | #define RXG_ERROR 29 47 | #define RXG_INPUT_END 30 48 | 49 | #define RXG_EXP 31 50 | #define RXG_TERM 32 51 | #define RXG_ELM 33 52 | #define RXG_SYM 34 53 | #define RXG_RANGE 35 54 | #define RXG_RANGE_ELM 36 55 | #define RXG_GRAMMAR 37 56 | #define RXG_PATTERN 38 57 | #define RXG_ACTION_SEQUENCE 39 58 | #define RXG_STMT_ACTION 40 59 | #define RXG_START_REGEX 41 60 | #define RXG_END_REGEX 42 61 | #define RXG_START_C_TOKENIZER 43 62 | #define RXG_END_C_TOKENIZER 44 63 | #define RXG_ACCEPT_WHITESPACE 45 64 | #define RXG_MODE 46 65 | #define RXG_MODE_LIST 47 66 | #define RXG_MODE_GROUP 48 67 | #define RXG_PATTERN_LIST 49 68 | 69 | 70 | struct rxg_stack { 71 | int error_recovery_:1; 72 | int pending_reset_:1; 73 | int discard_remaining_actions_:1; 74 | int slot_1_has_sym_data_:1; 75 | int slot_1_has_common_data_:1; 76 | int top_of_stack_has_sym_data_:1; 77 | int top_of_stack_has_common_data_:1; 78 | int newbuf_pos_has_common_data_:1; 79 | int newbuf_pos_has_sym_data_:1; 80 | int stack_newbuf_pos_has_common_data_:1; 81 | int stack_newbuf_pos_has_sym_data_:1; 82 | int action_preservation_; 83 | int current_err_action_; 84 | int slot_1_sym_; 85 | int continue_at_; 86 | int mute_error_turns_; 87 | size_t pos_, num_stack_allocated_; 88 | struct rxg_sym_data *stack_; 89 | struct rxg_sym_data *sym_data_; 90 | struct rxg_sym_data *new_buf_; 91 | size_t new_buf_num_allocated_; 92 | size_t new_buf_sym_partial_pos_; 93 | size_t current_production_length_; 94 | int current_production_nonterminal_; 95 | size_t sym_idx_; 96 | }; 97 | 98 | void rxg_stack_init(struct rxg_stack *stack); 99 | void rxg_stack_cleanup(struct rxg_stack *stack); 100 | int rxg_stack_reset(struct rxg_stack *stack); 101 | int rxg_stack_can_recover(struct rxg_stack *stack); 102 | int rxg_stack_accepts(struct rxg_stack *stack, int sym); 103 | int rxg_parse(struct rxg_stack *stack, int sym, struct prd_grammar *g, struct tkr_tokenizer *tkr, struct symbol_table *st, int char_value); 104 | 105 | #ifdef __cplusplus 106 | } /* extern "C" */ 107 | #endif 108 | 109 | #endif /* CARB_RXG_REGEX_GRAMMAR_H_INCLUDED */ 110 | -------------------------------------------------------------------------------- /src/report_error.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef STDLIB_H_INCULDED 17 | #define STDLIB_H_INCLUDED 18 | #include 19 | #endif 20 | 21 | #ifndef STDIO_H_INCLUDED 22 | #define STDIO_H_INCLUDED 23 | #include 24 | #endif 25 | 26 | #ifndef STDARG_H_INCLUDED 27 | #define STDARG_H_INCLUDED 28 | #include 29 | #endif 30 | 31 | #ifndef XLTS_H_INCLUDED 32 | #define XLTS_H_INCLUDED 33 | #include "xlts.h" 34 | #endif 35 | 36 | #ifndef TOKENIZER_H_INCLUDED 37 | #define TOKENIZER_H_INCLUDED 38 | #include "tokenizer.h" 39 | #endif 40 | 41 | #ifndef REPORT_ERROR_H_INCLUDED 42 | #define REPORT_ERROR_H_INCLUDED 43 | #include "report_error.h" 44 | #endif 45 | 46 | static void re_error_nowhere_impl(const char *fmt, va_list args) { 47 | vfprintf(stderr, fmt, args); 48 | fprintf(stderr, "\n"); 49 | } 50 | 51 | static void re_error_impl(const char *filename, int line_nr, int col_nr, const char *fmt, va_list args) { 52 | if (line_nr) { 53 | fprintf(stderr, "%s(%d): ", filename ? filename : "", line_nr); 54 | } 55 | else { 56 | fprintf(stderr, "%s(?): ", filename ? filename : ""); 57 | } 58 | re_error_nowhere_impl(fmt, args); 59 | } 60 | 61 | static int re_error_x_marks_the_spot(struct xlts *x) { 62 | struct xlts_chunk *ori_chunk; 63 | for (ori_chunk = x->chunks_; ori_chunk < (x->chunks_ + x->num_chunks_); ori_chunk++) { 64 | if (ori_chunk->ct_ != XLTS_XLAT) { 65 | /* Found chunk that has source location we can use. */ 66 | return 1; 67 | } 68 | } 69 | return 0; 70 | } 71 | 72 | static void re_error_x_impl(struct xlts *loc, const char *fmt, va_list args) { 73 | struct xlts_chunk *ori_chunk; 74 | for (ori_chunk = loc->chunks_; ori_chunk < (loc->chunks_ + loc->num_chunks_); ori_chunk++) { 75 | if (ori_chunk->ct_ != XLTS_XLAT) { 76 | /* Found chunk that has source location we can use. */ 77 | break; 78 | } 79 | } 80 | if (ori_chunk == (loc->chunks_ + loc->num_chunks_)) { 81 | ori_chunk = NULL; 82 | } 83 | 84 | if (ori_chunk) { 85 | re_error_impl(ori_chunk->filename_, ori_chunk->line_, ori_chunk->col_, fmt, args); 86 | } 87 | else { 88 | re_error_impl(NULL, 0, 0, fmt, args); 89 | } 90 | } 91 | 92 | void re_error_flc(const char *filename, int line, int col, const char *fmt, ...) { 93 | va_list args; 94 | va_start(args, fmt); 95 | 96 | re_error_impl(filename, line, col, fmt, args); 97 | 98 | va_end(args); 99 | } 100 | 101 | void re_error(struct xlts *loc, const char *fmt, ...) { 102 | va_list args; 103 | va_start(args, fmt); 104 | 105 | re_error_x_impl(loc, fmt, args); 106 | 107 | va_end(args); 108 | } 109 | 110 | void re_error_tkr(struct tkr_tokenizer *tkr, const char *fmt, ...) { 111 | va_list args; 112 | va_start(args, fmt); 113 | 114 | if (re_error_x_marks_the_spot(&tkr->xmatch_)) { 115 | re_error_x_impl(&tkr->xmatch_, fmt, args); 116 | } 117 | else { 118 | re_error_impl(tkr->filename_, tkr->start_line_, tkr->start_col_, fmt, args); 119 | } 120 | 121 | va_end(args); 122 | } 123 | 124 | void re_error_nowhere(const char *fmt, ...) { 125 | va_list args; 126 | va_start(args, fmt); 127 | re_error_nowhere_impl(fmt, args); 128 | va_end(args); 129 | } 130 | -------------------------------------------------------------------------------- /src/report_error.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef REPORT_ERROR_H 17 | #define REPORT_ERROR_H 18 | 19 | #ifndef XLTS_H_INCLUDED 20 | #define XLTS_H_INCLUDED 21 | #include "xlts.h" 22 | #endif 23 | 24 | #ifndef TOKENIZER_H_INCLUDED 25 | #define TOKENIZER_H_INCLUDED 26 | #include "tokenizer.h" 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /* Report using xlts as location reference */ 34 | void re_error(struct xlts *where, const char *fmt, ...); 35 | 36 | /* Report using the last matched xlts (tkr->xmatch_) as location reference */ 37 | void re_error_tkr(struct tkr_tokenizer *tkr, const char *fmt, ...); 38 | 39 | /* Report using explicit file, line, column location reference */ 40 | void re_error_flc(const char *filename, int line, int col, const char *fmt, ...); 41 | 42 | /* Report error without any specific location associated */ 43 | void re_error_nowhere(const char *fmt, ...); 44 | 45 | #ifdef __cplusplus 46 | } /* extern "C" */ 47 | #endif 48 | 49 | #endif /* REPORT_ERROR_H */ 50 | -------------------------------------------------------------------------------- /src/rex_set_range.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef REX_SET_RANGE_H 17 | #define REX_SET_RANGE_H 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | struct uc_cat_range; 24 | 25 | struct rex_set_interval { 26 | int from_, to_; 27 | }; 28 | 29 | struct rex_set_range { 30 | size_t num_intervals_; 31 | size_t num_intervals_allocated_; 32 | struct rex_set_interval *intervals_; 33 | }; 34 | 35 | void rex_set_range_init(struct rex_set_range *range); 36 | void rex_set_range_cleanup(struct rex_set_range *range); 37 | 38 | /* Swaps the contents of the two rex set ranges */ 39 | void rex_set_range_swap(struct rex_set_range *a, struct rex_set_range *b); 40 | 41 | /* Adds the given range to the set; from and to are inclusive. */ 42 | int rex_set_range_add(struct rex_set_range *range, int from, int to); 43 | 44 | /* Merges the two ranges */ 45 | int rex_set_range_add_range(struct rex_set_range *range, const struct rex_set_range *other); 46 | 47 | /* Resets "range", adds the given unicode ranges to it, combining them, and then optionally inverts the range. 48 | * first and last index g_uc_cat_ranges_[] (see uc_cat_ranges.h). */ 49 | int rex_set_range_unicode(struct rex_set_range *range, size_t first, size_t last, int invert); 50 | 51 | /* Inverts the range over the unicode codepoint range; e.g. if the old set range had only 52 | * the 0x20 space character, the new range would be 0-0x1F; 0x21-0x10FFFF. */ 53 | int rex_set_range_unicode_invert(struct rex_set_range *range); 54 | 55 | #ifdef __cplusplus 56 | } /* extern "C" */ 57 | #endif 58 | 59 | #endif /* REX_SET_RANGE_H */ 60 | -------------------------------------------------------------------------------- /src/scanner.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef SCANNER_H 17 | #define SCANNER_H 18 | 19 | #ifndef STDIO_H_INCLUDED 20 | #define STDIO_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | #ifndef STDDEF_H_INCLUDED 25 | #define STDDEF_H_INCLUDED 26 | #include /* size_t */ 27 | #endif 28 | 29 | #ifndef STDINT_H_INCLUDED 30 | #define STDINT_H_INCLUDED 31 | #include 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif /* __cplusplus */ 37 | 38 | struct sc_scanner { 39 | /* Number of states for the scanner, including the dummy 40 | * 0 state. */ 41 | size_t num_states; 42 | 43 | /* State at which to start scanning */ 44 | size_t start_state; 45 | 46 | /* Transition table, each row is 256 cells (one for each 47 | * possible input byte) - there are num_states + 1 rows. 48 | * For any given state index as row, and any given column 49 | * as the next input byte from that state, the cell gives 50 | * the state to transition to upon accepting the input. 51 | * State 0 is unused, it's row can be ignored. The value 52 | * 0 in a cell indicates that byte is not acceptable input 53 | * in the given state. */ 54 | size_t *transition_table; 55 | 56 | /* Actions for each state */ 57 | struct sc_action *actions; 58 | 59 | /* Recognize those states with no rules being matches */ 60 | size_t default_action; 61 | }; 62 | 63 | struct sc_action { 64 | /* Field typically used to store the primary action, eg. the token 65 | * value that is matched. 66 | * If this equals default_action, there is no action for the corresponding state, 67 | * the valid actions must therefore not be equal to default_action. 68 | * default_action is passed as an argument to sc_scanner_compile and 69 | * stored in sc_scanner::default_action */ 70 | uintptr_t action; 71 | 72 | /* Field typically used to store the variant of the primary action, 73 | * for instance, it may be helpful to distinguish the matching 74 | * of 123 (decimals) vs. 0123 (octals) vs. 0x123 (hexadecimals) as, even 75 | * though the corresponding action would be the same (they're integers), 76 | * the parsing needed to convert the value to its binary representation 77 | * is different. If action equals default_action, the value of the 78 | * variant is undefined. */ 79 | uintptr_t variant; 80 | }; 81 | 82 | struct sc_scan_rule { 83 | const char *regexp; 84 | 85 | /* Action if the regexp rule is matched before any other in 86 | * the rules table. */ 87 | struct sc_action action; 88 | }; 89 | 90 | void sc_scanner_init(struct sc_scanner *sc); 91 | void sc_scanner_cleanup(struct sc_scanner *sc); 92 | 93 | int sc_scanner_compile(struct sc_scanner *sc, uintptr_t default_action, size_t num_rules, const struct sc_scan_rule *rules); 94 | void sc_scanner_dump(struct sc_scanner *sc); 95 | 96 | void sc_scanner_write_to_c_file(struct sc_scanner *sc, FILE *fp, const char *transition_table_id, const char *state_actions_id, const char *scanner_id); 97 | 98 | #ifdef __cplusplus 99 | } /* extern "C" */ 100 | #endif 101 | 102 | #endif /* SCANNER_H */ 103 | -------------------------------------------------------------------------------- /src/snippet.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef SNIPPET_H 17 | #define SNIPPET_H 18 | 19 | #ifndef STDDEF_H_INCLUDED 20 | #define STDDEF_H_INCLUDED 21 | #include /* size_t */ 22 | #endif 23 | 24 | #ifndef STDINT_H_INCLUDED 25 | #define STDINT_H_INCLUDED 26 | #include 27 | #endif 28 | 29 | #ifndef XLTS_H_INCLUDED 30 | #define XLTS_H_INCLUDED 31 | #include "xlts.h" 32 | #endif 33 | 34 | #ifndef TOKENIZER_H_INCLUDED 35 | #define TOKENIZER_H_INCLUDED 36 | #include "tokenizer.h" 37 | #endif 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | struct snippet_token { 44 | uintptr_t match_; 45 | uintptr_t variant_; 46 | struct xlts text_; 47 | }; 48 | 49 | struct snippet { 50 | /* Tokens that make up the snippet of code */ 51 | size_t num_tokens_; 52 | size_t num_tokens_allocated_; 53 | struct snippet_token *tokens_; 54 | }; 55 | 56 | void snippet_init(struct snippet *s); 57 | void snippet_cleanup(struct snippet *s); 58 | void snippet_move(struct snippet *dst, struct snippet *src); 59 | void snippet_clear(struct snippet *s); 60 | int snippet_append(struct snippet *s, uintptr_t match, uintptr_t variant, struct xlts *token); 61 | int snippet_append_tkr(struct snippet *s, struct tkr_tokenizer *tkr); 62 | int snippet_append_snippet(struct snippet *d, const struct snippet *s); 63 | void snippet_pop_last_token(struct snippet *s); 64 | void snippet_pop_first_token(struct snippet *s); 65 | uint64_t snippet_hash(const struct snippet *s); 66 | int snippet_cmp(const struct snippet *left, const struct snippet *right); 67 | char *snippet_dup_xlt(const struct snippet *s); 68 | int snippet_append_to_xlts(struct xlts *x, const struct snippet *s); 69 | 70 | #ifdef __cplusplus 71 | } /* extern "C" */ 72 | #endif 73 | 74 | #endif /* SNIPPET_H */ 75 | -------------------------------------------------------------------------------- /src/symbol.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef SYMBOL_H 17 | #define SYMBOL_H 18 | 19 | #ifndef XLTS_H_INCLUDED 20 | #define XLTS_H_INCLUDED 21 | #include "xlts.h" 22 | #endif 23 | 24 | #ifndef SNIPPET_H_INCLUDED 25 | #define SNIPPET_H_INCLUDED 26 | #include "snippet.h" 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #define SYMBOL_TABLE_SIZE 127 34 | 35 | typedef enum sym_type_enum { 36 | SYM_UNDEFINED, 37 | SYM_TERMINAL, 38 | SYM_NONTERMINAL 39 | } sym_type_t; 40 | 41 | struct symbol { 42 | /* Type of symbol, either terminal or non-terminal */ 43 | sym_type_t st_; 44 | 45 | /* Name and source location of definition */ 46 | struct xlts def_; 47 | 48 | /* Assigned symbol ordinal for generating tables */ 49 | int ordinal_; 50 | 51 | /* Next in symbol_table::terminals_ or symbol_table::non_terminals_ */ 52 | struct symbol *next_; 53 | 54 | /* Next in hash table */ 55 | struct symbol *hash_chain_; 56 | 57 | /* Snippet describing target language specific type string assigned to symbol. 58 | * The snippet may hold a single "$" TOK_SPECIAL_IDENT as a placeholder for 59 | * the declarator identifier of such a type string. If no such a placeholder 60 | * is found, the placeholder for the identifier is implied at the end. */ 61 | struct snippet type_snippet_; 62 | 63 | /* Assigned type; representing both the type (as type_snippet) and its field 64 | * value in the union of symbol data on the stack. */ 65 | struct typestr *assigned_type_; 66 | }; 67 | 68 | struct symbol_table { 69 | struct symbol *hash_table_[SYMBOL_TABLE_SIZE]; 70 | 71 | /* Terminals and non-terminals in order of declaration */ 72 | struct symbol *terminals_; 73 | struct symbol *non_terminals_; 74 | }; 75 | 76 | void symbol_table_init(struct symbol_table *st); 77 | void symbol_table_cleanup(struct symbol_table *st); 78 | void symbol_init(struct symbol *sym); 79 | void symbol_cleanup(struct symbol *sym); 80 | 81 | /* Returns NULL upon error, or the symbol that was either found or newly created. 82 | * To distinguish between an existing symbol and one that was created, the flag 83 | * *is_new is set if a new symbol was created, and cleared if an existing symbol 84 | * was found. Note that the existing symbol might not be of the same symtype. */ 85 | struct symbol *symbol_find_or_add(struct symbol_table *st, sym_type_t symtype, struct xlts *id, int *is_new); 86 | 87 | /* Finds a symbol, returns NULL if the symbol could not be found. */ 88 | struct symbol *symbol_find(struct symbol_table *st, const char *id); 89 | 90 | /* Finds a symbol by its ordinal value (note: inefficient O(n) implementation!) */ 91 | struct symbol *symbol_find_by_ordinal(struct symbol_table *st, int n); 92 | 93 | #ifdef __cplusplus 94 | } /* extern "C" */ 95 | #endif 96 | 97 | #endif /* SYMBOL_H */ 98 | -------------------------------------------------------------------------------- /src/temp_output.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef TEMP_OUTPUT_H 17 | #define TEMP_OUTPUT_H 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #ifndef STDIO_H_INCLUDED 24 | #define STDIO_H_INCLUDED 25 | #include 26 | #endif 27 | 28 | FILE *to_make_temp(const char *final_destination_file, char **temp_filenamep); 29 | 30 | char *to_derive_temp_name(const char *final_destination_name); 31 | 32 | #ifdef __cplusplus 33 | } /* extern "C" */ 34 | #endif 35 | 36 | #endif /* TEMP_OUTPUT_H */ 37 | -------------------------------------------------------------------------------- /src/tokenizer.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef TOKENIZER_H 17 | #define TOKENIZER_H 18 | 19 | #ifndef STDINT_H_INCLUDED 20 | #define STDINT_H_INCLUDED 21 | #include 22 | #endif 23 | 24 | #ifndef STDDEF_H_INCLUDED 25 | #define STDDEF_H_INCLUDED 26 | #include /* size_t */ 27 | #endif 28 | 29 | #ifndef SCANNER_H_INCLUDED 30 | #define SCANNER_H_INCLUDED 31 | #include "scanner.h" 32 | #endif 33 | 34 | #ifndef XLTS_H_INCLUDED 35 | #define XLTS_H_INCLUDED 36 | #include "xlts.h" 37 | #endif 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | #define TKR_END_OF_INPUT 0 44 | #define TKR_MATCH 1 45 | #define TKR_SYNTAX_ERROR 2 46 | #define TKR_INTERNAL_ERROR 3 47 | #define TKR_FEED_ME 4 48 | 49 | struct tkr_tokenizer { 50 | /* Scanner that implements the lexical rules */ 51 | const struct sc_scanner *scanner_; 52 | 53 | int have_private_scanner_ : 1; 54 | 55 | /* State of scanner during lexical scanning */ 56 | size_t state_; 57 | 58 | /* Current index in the input buffer passed to tkr_tokenizer_input */ 59 | size_t input_index_; 60 | 61 | /* Stream offset, line and column of next byte of input */ 62 | size_t input_offset_; 63 | int input_line_, input_col_; 64 | 65 | struct xlts xmatch_; 66 | struct xlts_clamp xmatch_token_clamp_; 67 | 68 | /* Current index in the match_ buffer during processing */ 69 | size_t match_index_; 70 | 71 | /* The value originally at the null terminator at index token_size_ of 72 | * the match_ buffer. */ 73 | char null_terminator_repair_; 74 | 75 | /* Size of the token in match_, valid only after TKR_MATCH is returned 76 | * from tkr_tokenizer_input(). */ 77 | size_t token_size_; 78 | 79 | /* Filename of the input. May be set directly by callers; does not 80 | * influence lexical scanning directly. */ 81 | const char *filename_; 82 | 83 | /* Offset, in bytes, to the first character of the match within the input 84 | * stream. */ 85 | size_t start_offset_; 86 | 87 | /* Line and column of the first character of the match, may be used 88 | * for error reporting or highlighting. */ 89 | int start_line_, start_col_; 90 | 91 | /* Current offset, line and column in the input stream. */ 92 | size_t offset_; 93 | int line_, col_; 94 | 95 | /* Best matched action, or scanner_.default_action if no match was (yet) 96 | * found. best_match_variant_ contains the variant of the best matched 97 | * action (see scanner.h sc_action comments for a discussion of action and 98 | * variant.) */ 99 | uintptr_t best_match_action_; 100 | uintptr_t best_match_variant_; 101 | 102 | /* Size of the current best match */ 103 | size_t best_match_size_; 104 | 105 | /* Offset, line and column of the first character *after* the current 106 | * best match */ 107 | size_t best_match_offset_; 108 | int best_match_line_, best_match_col_; 109 | }; 110 | 111 | 112 | void tkr_tokenizer_init(struct tkr_tokenizer *tkr, const struct sc_scanner *scanner); 113 | 114 | void tkr_tokenizer_cleanup(struct tkr_tokenizer *tkr); 115 | 116 | void tkr_tokenizer_switch(struct tkr_tokenizer *tkr, const struct sc_scanner *scanner); 117 | 118 | /* Clear any prior partial buffered state from tokenizer; input_line_, input_col_ and 119 | * input_offset_ are *retained*. */ 120 | void tkr_tokenizer_reset(struct tkr_tokenizer *tkr); 121 | 122 | int tkr_tokenizer_inputs(struct tkr_tokenizer *tkr, const char *input, size_t input_size, int is_final_input); 123 | int tkr_tokenizer_inputx(struct tkr_tokenizer *tkr, struct xlts *input, int is_final_input); 124 | 125 | const char *tkr_str(const struct tkr_tokenizer *tkr); 126 | 127 | #ifdef __cplusplus 128 | } /* extern "C" */ 129 | #endif 130 | 131 | #endif /* TOKENIZER_H */ 132 | -------------------------------------------------------------------------------- /src/typestr.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef STDIO_H_INCLUDED 17 | #define STDIO_H_INCLUDED 18 | #include 19 | #endif 20 | 21 | #ifndef STDLIB_H_INCLUDED 22 | #define STDLIB_H_INCLUDED 23 | #include 24 | #endif 25 | 26 | #ifndef STDINT_H_INCLUDED 27 | #define STDINT_H_INCLUDED 28 | #include 29 | #endif 30 | 31 | #ifndef SNIPPET_H_INCLUDED 32 | #define SNIPPET_H_INCLUDED 33 | #include "snippet.h" 34 | #endif 35 | 36 | #ifndef REPORT_ERROR_H_INCLUDED 37 | #define REPORT_ERROR_H_INCLUDED 38 | #include "report_error.h" 39 | #endif 40 | 41 | #ifndef TYPESTR_H_INCLUDED 42 | #define TYPESTR_H_INCLUDED 43 | #include "typestr.h" 44 | #endif 45 | 46 | static void typestr_init(struct typestr *ts); 47 | static void typestr_cleanup(struct typestr *ts); 48 | 49 | void typestr_table_init(struct typestr_table *tt) { 50 | tt->num_typestrs_ = tt->num_typestrs_allocated_ = 0; 51 | tt->typestrs_ = NULL; 52 | } 53 | 54 | void typestr_table_cleanup(struct typestr_table *tt) { 55 | size_t n; 56 | for (n = 0; n < tt->num_typestrs_; ++n) { 57 | struct typestr *ts = tt->typestrs_[n]; 58 | 59 | typestr_cleanup(ts); 60 | free(ts); 61 | } 62 | 63 | if (tt->typestrs_) free(tt->typestrs_); 64 | } 65 | 66 | static void typestr_init(struct typestr *ts) { 67 | ts->is_symbol_type_ = 0; 68 | ts->is_raii_constructor_ = 0; 69 | snippet_init(&ts->typestr_snippet_); 70 | ts->ordinal_ = 0; 71 | snippet_init(&ts->constructor_snippet_); 72 | snippet_init(&ts->move_snippet_); 73 | snippet_init(&ts->destructor_snippet_); 74 | snippet_init(&ts->token_action_snippet_); 75 | snippet_init(&ts->visit_snippet_); 76 | } 77 | 78 | static void typestr_cleanup(struct typestr *ts) { 79 | snippet_cleanup(&ts->typestr_snippet_); 80 | snippet_cleanup(&ts->constructor_snippet_); 81 | snippet_cleanup(&ts->destructor_snippet_); 82 | snippet_cleanup(&ts->token_action_snippet_); 83 | snippet_cleanup(&ts->visit_snippet_); 84 | } 85 | 86 | struct typestr *typestr_add(struct typestr_table *tt, const struct snippet *typestr_snippet) { 87 | /* Add new */ 88 | if (tt->num_typestrs_ == tt->num_typestrs_allocated_) { 89 | size_t new_num = tt->num_typestrs_allocated_ * 2 + 1; 90 | if (new_num <= tt->num_typestrs_allocated_) { 91 | re_error_nowhere("Error, overflow"); 92 | return NULL; 93 | } 94 | if (new_num > (SIZE_MAX / sizeof(struct typestr *))) { 95 | re_error_nowhere("Error, overflow"); 96 | return NULL; 97 | } 98 | size_t alloc_size = new_num * sizeof(struct typestr *); 99 | void *p = realloc(tt->typestrs_, alloc_size); 100 | if (!p) { 101 | re_error_nowhere("Error, no memory"); 102 | return NULL; 103 | } 104 | tt->typestrs_ = (struct typestr **)p; 105 | tt->num_typestrs_allocated_ = new_num; 106 | } 107 | struct typestr *ts; 108 | ts = (struct typestr *)malloc(sizeof(struct typestr)); 109 | if (!ts) { 110 | re_error_nowhere("Error, no memory"); 111 | return NULL; 112 | } 113 | typestr_init(ts); 114 | tt->typestrs_[tt->num_typestrs_] = ts; 115 | ts->ordinal_ = (int)tt->num_typestrs_++; 116 | 117 | int r; 118 | r = snippet_append_snippet(&ts->typestr_snippet_, typestr_snippet); 119 | if (r) { 120 | typestr_cleanup(ts); 121 | free(ts); 122 | return NULL; 123 | } 124 | 125 | return ts; 126 | } 127 | -------------------------------------------------------------------------------- /src/typestr.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef TYPESTR_H 17 | #define TYPESTR_H 18 | 19 | #ifndef SNIPPET_H_INCLUDED 20 | #define SNIPPET_H_INCLUDED 21 | #include "snippet.h" 22 | #endif 23 | 24 | #ifndef STDDEF_H_INCLUDED 25 | #define STDDEF_H_INCLUDED 26 | #include /* size_t */ 27 | #endif 28 | 29 | #ifndef STDINT_H_INCLUDED 30 | #define STDINT_H_INCLUDED 31 | #include /* uint64_t */ 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #define TYPESTR_TABLE_SIZE 127 39 | 40 | struct typestr { 41 | /* Non-zero if this is a symbol type (a type associated with 42 | * a particular set of symbols, but not all.) */ 43 | int is_symbol_type_:1; 44 | 45 | /* If non-zero, the constructor will not be considered complete 46 | * if the code snippet exits the parse or scan functions. 47 | * RAII refers to Resource Acquisition Is Initialization and implies 48 | * that during construction, an exception may be thrown. If an 49 | * exception is thrown, any partial construction is unwound and 50 | * the exception passes transparently through Carburetta's generated 51 | * C-style code. Because the type is not constructed, it is important 52 | * that the destructor is *only* called if construction completes 53 | * normally (i.e. execution of the constructor completes to the end.) 54 | * The counter example, is_raii_constructor_==0, handles the case 55 | * where the caller is responsible for part of the construction. In 56 | * such a scenario, returning out of the parse of scan function is 57 | * a sign that the constructor completed, not failed, and any 58 | * subsequent cleanup must called the destructor. */ 59 | int is_raii_constructor_:1; 60 | 61 | /* Sequence of tokens that make up the type description, may 62 | * contain a single "$" TOK_SPECIAL_IDENT to denote the position 63 | * at which the identifier would appear. If no "$" placeholder 64 | * exists, one is implied to exist at the end of the snippet. 65 | * Note that a "$" placeholder may not explicitly exist at the 66 | * end of the snippet as this would remove the uniqueness of 67 | * a type definition. */ 68 | struct snippet typestr_snippet_; 69 | 70 | int ordinal_; 71 | 72 | struct snippet constructor_snippet_; 73 | struct snippet move_snippet_; 74 | struct snippet destructor_snippet_; 75 | struct snippet token_action_snippet_; 76 | struct snippet visit_snippet_; 77 | }; 78 | 79 | struct typestr_table { 80 | /* Array of pointers for all typestrs, index of array corresponds to typestr ordinal. */ 81 | size_t num_typestrs_; 82 | size_t num_typestrs_allocated_; 83 | struct typestr **typestrs_; /* NOTE: Array of pointers, not objects, so we don't disturb the hash lists */ 84 | }; 85 | 86 | void typestr_table_init(struct typestr_table *tt); 87 | void typestr_table_cleanup(struct typestr_table *tt); 88 | 89 | struct typestr *typestr_add(struct typestr_table *tt, const struct snippet *typestr_snippet); 90 | 91 | #ifdef __cplusplus 92 | } /* extern "C" */ 93 | #endif 94 | 95 | #endif /* TYPESTR_H */ 96 | -------------------------------------------------------------------------------- /src/uc_cat_ranges.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | #ifndef UC_CAT_RANGES_H 16 | #define UC_CAT_RANGES_H 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #ifndef STDINT_H_INCLUDED 23 | #define STDINT_H_INCLUDED 24 | #include 25 | #endif 26 | 27 | struct uc_cat_interval { 28 | int from_, to_; 29 | }; 30 | 31 | struct uc_cat_range { 32 | const char *short_name_, *long_name_; 33 | const char *short_group_, *long_group_; 34 | size_t num_intervals_; 35 | const struct uc_cat_interval *intervals_; 36 | }; 37 | 38 | extern const struct uc_cat_range *g_uc_cat_ranges_[]; 39 | extern const size_t g_uc_cat_range_num_; 40 | 41 | /* Looks in the g_uc_cat_ranges_[] array for a match on name on any of short_name_, long_name_, short_group_ and long_group_, 42 | * and returns the index-range of the ranges that match in first_range_index and last_range_index respectively. 43 | * If no range matches, returns 0, if at least one matching range is found, non-zero is returned. 44 | * If you examine g_uc_cat_ranges_[] in the C file, you'll notice that short_name_ and long_name_ are all unique, and only 45 | * short_group_ and long_group_ are shared between ranges, so you'll only get multiple ranges when specifying a group. 46 | * Finally, note that name can be the substring of a larger string (and so does not need to be null-terminated) as its 47 | * length is explicitly passed in. */ 48 | int uc_cat_ranges_resolve_codepoint_category(const char *name, size_t len, size_t *first_range_index, size_t *last_range_index); 49 | 50 | #ifdef __cplusplus 51 | } /* extern "C" */ 52 | #endif 53 | 54 | #endif /* UC_CAT_RANGES_H */ 55 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef VERSION_H 17 | #define VERSION_H 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #define CARBURETTA_MAJOR_VER 0 24 | #define CARBURETTA_MINOR_VER 8 25 | #define CARBURETTA_PATCH_VER 27 26 | 27 | #define CARBURETTA_STRINGIFY_i(x) #x 28 | #define CARBURETTA_STRINGIFY(x) CARBURETTA_STRINGIFY_i(x) 29 | 30 | #if CARBURETTA_PATCH_VER & 1 31 | // Odd patch version means development version 32 | #define CARBURETTA_VERSION_STR CARBURETTA_STRINGIFY(CARBURETTA_MAJOR_VER) "." CARBURETTA_STRINGIFY(CARBURETTA_MINOR_VER) "." CARBURETTA_STRINGIFY(CARBURETTA_PATCH_VER) " (development)" 33 | #else 34 | #define CARBURETTA_VERSION_STR CARBURETTA_STRINGIFY(CARBURETTA_MAJOR_VER) "." CARBURETTA_STRINGIFY(CARBURETTA_MINOR_VER) "." CARBURETTA_STRINGIFY(CARBURETTA_PATCH_VER) 35 | #endif 36 | 37 | #define CARBURETTA_COPYRIGHT_STR "(C) 2020-2025 Kinglet B.V." 38 | 39 | #ifdef __cplusplus 40 | } /* extern "C" */ 41 | #endif 42 | 43 | #endif /* VERSION_H */ 44 | -------------------------------------------------------------------------------- /tester/cpp/t12.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include // atoi 17 | 18 | namespace nt12 { 19 | 20 | // Value object for all symbols (terminals and non-terminals.) 21 | class Value { 22 | public: 23 | static size_t open_value_count_; 24 | int value_ = 0; 25 | Value() : Value(0) {} 26 | Value(int val) : value_(val) { 27 | open_value_count_++; 28 | } 29 | ~Value() { 30 | --open_value_count_; 31 | } 32 | int value() const { return value_; } 33 | void set_value(int value) { value_ = value; } 34 | Value operator+(const Value &r) const { return Value(value() + r.value()); } 35 | Value operator-(const Value &r) const { return Value(value() - r.value()); } 36 | Value operator*(const Value &r) const { return Value(value() * r.value()); } 37 | Value operator/(const Value &r) const { return Value(value() / r.value()); } 38 | Value operator-() const { return Value(-value()); } 39 | Value &operator=(const Value &r) { 40 | set_value(r.value()); 41 | return *this; 42 | } 43 | }; 44 | 45 | size_t Value::open_value_count_ = 0; 46 | 47 | } // namespace nt12 48 | 49 | using namespace nt12; 50 | 51 | %scanner% 52 | %prefix t12_ 53 | 54 | INTEGER: [0-9]+ { $ = Value(atoi($text)); } 55 | 56 | : [\ \n]+; /* skip spaces and newlines */ 57 | PLUS: \+; 58 | MINUS: \-; 59 | ASTERISK: \*; 60 | SLASH: /; 61 | PAR_OPEN: \(; 62 | PAR_CLOSE: \); 63 | 64 | %token PLUS MINUS ASTERISK SLASH PAR_OPEN PAR_CLOSE INTEGER 65 | %nt grammar expr term factor value 66 | 67 | %grammar% 68 | 69 | %common_class Value 70 | 71 | %params int &final_result 72 | 73 | grammar: expr { 74 | final_result = ${0}.value(); 75 | } 76 | 77 | expr: term { $ = ${0}; } 78 | expr: expr PLUS term { $ = ${0} + ${2}; } 79 | expr: expr MINUS term { $ = ${0} - ${2}; } 80 | 81 | term: factor { $ = ${0}; } 82 | term: term ASTERISK factor { $ = ${0} * ${2}; } 83 | term: term SLASH factor { $ = ${0} / ${2}; } 84 | 85 | factor: value { $ = ${0}; } 86 | factor: MINUS factor { $ = -${1}; } 87 | factor: PAR_OPEN expr PAR_CLOSE { $ = ${1}; } 88 | 89 | value: INTEGER { $ = ${0}; } 90 | 91 | %% 92 | 93 | extern "C" int t12() { 94 | int rv = -1; 95 | int r; 96 | 97 | const char sum[] = "1+2*-3"; 98 | 99 | struct t12_stack stack; 100 | t12_stack_init(&stack); 101 | 102 | t12_set_input(&stack, sum, sizeof(sum) - 1, 1); 103 | int final_result = 0; 104 | r = t12_scan(&stack, final_result); 105 | if (r != _T12_FINISH) { 106 | rv = -2; 107 | goto fail; 108 | } 109 | if (final_result != -5) { 110 | rv = -3; 111 | goto fail; 112 | } 113 | 114 | /* At this point, the only object that should exist on the stack 115 | * is the grammar object; all value objects should be cleaned up. */ 116 | if (Value::open_value_count_ != 1) { 117 | rv = -4; 118 | goto fail; 119 | } 120 | /* Resetting the stack should clear out the only object on the stack, 121 | * being, the grammar object. */ 122 | t12_stack_reset(&stack); 123 | 124 | if (Value::open_value_count_ != 0) { 125 | rv = -5; 126 | goto fail; 127 | } 128 | 129 | rv = 0; 130 | 131 | fail: 132 | t12_stack_cleanup(&stack); 133 | return rv; 134 | } 135 | 136 | -------------------------------------------------------------------------------- /tester/cpp/t16.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // t16 - we want a simple %type without %move to not call a destructor on the 17 | // source material. 18 | 19 | #include // fprintf, stderr 20 | #include // SIZE_MAX 21 | #include 22 | #include // atoi 23 | #include // std::exception 24 | 25 | namespace nt16 { 26 | 27 | } // namespace nt16 28 | 29 | using namespace nt16; 30 | 31 | int g_test_failed_ = 0; 32 | 33 | %scanner% 34 | %prefix t16_ 35 | 36 | DIGIT: [0-9] { $$ = atoi($text); } 37 | 38 | : [\ \n] +; /* skip spaces and newlines */ 39 | 40 | %token DIGIT 41 | %nt sequence result 42 | 43 | %grammar% 44 | 45 | /* We test a sequence of digits, a DIGIT is an int, it has a constructor and a destructor, but no %move, 46 | * consequently, its destructor should not be called after the item has been moved (because the item is 47 | * an implied memcpy.) */ 48 | 49 | %type DIGIT sequence: int 50 | %constructor $$ = 0; 51 | %destructor if ($$) { \ 52 | g_test_failed_ = 1; /* destructor called on non-zero digit, indicates failure.*/ \ 53 | } 54 | 55 | %params int &final_result 56 | 57 | result: sequence { 58 | final_result = $0; 59 | $0 = 0; 60 | } 61 | 62 | /* Sequence is just the addition of one or more digits, each production clears the digit and sequence used to 0, 63 | * so there should not be any issue on the %destructor for them. */ 64 | sequence: DIGIT { $$ = $0; $0 = 0; } 65 | sequence: sequence DIGIT { $$ = $0 + $1; $0 = $1 = 0; } 66 | 67 | %% 68 | 69 | extern "C" int t16() { 70 | int rv = -1; 71 | int r; 72 | 73 | const char sum[] = "123"; 74 | 75 | struct t16_stack stack; 76 | t16_stack_init(&stack); 77 | 78 | t16_set_input(&stack, sum, sizeof(sum) - 1, 1); 79 | int final_result = 0; 80 | 81 | r = t16_scan(&stack, final_result); 82 | if (r != _T16_FINISH) { 83 | rv = -1; 84 | goto fail; 85 | } 86 | 87 | if (g_test_failed_) { 88 | /* a %destructor complained */ 89 | rv = -2; 90 | goto fail; 91 | } 92 | 93 | if (final_result != 6) { 94 | /* 1 + 2 + 3 should equal 6 */ 95 | rv = -3; 96 | goto fail; 97 | } 98 | 99 | rv = 0; 100 | 101 | fail: 102 | t16_stack_cleanup(&stack); 103 | return rv; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /tester/cpp/t17.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // t17 - whereas t16 tests that we want a simple %type without %move to not call 17 | // a destructor on the source material, with t17 we want to test that a simple 18 | // %type *with* a %move will still always call the destructor on the souce material. 19 | 20 | #include // fprintf, stderr 21 | #include // SIZE_MAX 22 | #include 23 | #include // atoi 24 | #include // std::exception 25 | 26 | namespace nt17 { 27 | 28 | int g_num_move_calls_open_ = 0; 29 | 30 | } // namespace nt17 31 | 32 | using namespace nt17; 33 | 34 | %scanner% 35 | %prefix t17_ 36 | 37 | DIGIT: [0-9] { $$ = atoi($text); } 38 | 39 | : [\ \n] +; /* skip spaces and newlines */ 40 | 41 | %token DIGIT 42 | %nt sequence result 43 | 44 | %grammar% 45 | 46 | /* We test a sequence of digits, a DIGIT is an int, it has a constructor and a destructor, but no %move, 47 | * consequently, its destructor should not be called after the item has been moved (because the item is 48 | * an implied memcpy.) */ 49 | 50 | %type DIGIT sequence: int 51 | %constructor $$ = 0; 52 | %move $$ = $0; $0 = -1; g_num_move_calls_open_++; 53 | %destructor if ($$) { \ 54 | if ($$ == -1) --g_num_move_calls_open_; \ 55 | } 56 | 57 | %params int &final_result 58 | 59 | result: sequence { 60 | final_result = $0; 61 | $0 = 0; 62 | } 63 | 64 | /* Sequence is just the addition of one or more digits, each production clears the digit and sequence used to 0, 65 | * so there should not be any issue on the %destructor for them. */ 66 | sequence: DIGIT { $$ = $0; $0 = 0; } 67 | sequence: sequence DIGIT { $$ = $0 + $1; $0 = $1 = 0; } 68 | 69 | %% 70 | 71 | extern "C" int t17() { 72 | int rv = -1; 73 | int r; 74 | 75 | const char sum[] = "123"; 76 | 77 | struct t17_stack stack; 78 | t17_stack_init(&stack); 79 | 80 | t17_set_input(&stack, sum, sizeof(sum) - 1, 1); 81 | int final_result = 0; 82 | 83 | r = t17_scan(&stack, final_result); 84 | if (r != _T17_FINISH) { 85 | rv = -1; 86 | goto fail; 87 | } 88 | 89 | if (final_result != 6) { 90 | /* 1 + 2 + 3 should equal 6 */ 91 | rv = -3; 92 | goto fail; 93 | } 94 | 95 | rv = 0; 96 | 97 | fail: 98 | t17_stack_cleanup(&stack); 99 | return rv; 100 | } 101 | 102 | -------------------------------------------------------------------------------- /tester/cpp/t8.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include // atoi 17 | 18 | // stub object to keep count of how many 'grammar' nonterminals we have alive. 19 | class GrammarObj { 20 | public: 21 | static size_t open_grammar_count_; 22 | GrammarObj() { open_grammar_count_++; } 23 | ~GrammarObj() { open_grammar_count_--; } 24 | }; 25 | 26 | // Value object for all valued nonterminals and the INTEGER terminal. 27 | class Value { 28 | public: 29 | static size_t open_value_count_; 30 | int value_ = 0; 31 | Value() : Value(0) {} 32 | Value(int val) : value_(val) { 33 | open_value_count_++; 34 | } 35 | ~Value() { 36 | --open_value_count_; 37 | } 38 | int value() const { return value_; } 39 | void set_value(int value) { value_ = value; } 40 | Value operator+(const Value &r) const { return Value(value() + r.value()); } 41 | Value operator-(const Value &r) const { return Value(value() - r.value()); } 42 | Value operator*(const Value &r) const { return Value(value() * r.value()); } 43 | Value operator/(const Value &r) const { return Value(value() / r.value()); } 44 | Value operator-() const { return Value(-value()); } 45 | Value &operator=(const Value &r) { 46 | set_value(r.value()); 47 | return *this; 48 | } 49 | }; 50 | 51 | size_t Value::open_value_count_ = 0; 52 | size_t GrammarObj::open_grammar_count_ = 0; 53 | 54 | %scanner% 55 | %prefix t8_ 56 | 57 | INTEGER: [0-9]+ { $$ = Value(atoi($text)); } 58 | 59 | : [\ \n]+; /* skip spaces and newlines */ 60 | PLUS: \+; 61 | MINUS: \-; 62 | ASTERISK: \*; 63 | SLASH: /; 64 | PAR_OPEN: \(; 65 | PAR_CLOSE: \); 66 | 67 | %token PLUS MINUS ASTERISK SLASH PAR_OPEN PAR_CLOSE INTEGER 68 | %nt grammar expr term factor value 69 | 70 | %grammar% 71 | 72 | %class expr term factor value INTEGER: Value 73 | 74 | %class grammar: GrammarObj 75 | 76 | %params int &final_result 77 | 78 | grammar: expr { 79 | final_result = $0.value(); 80 | } 81 | 82 | expr: term { $$ = $0; } 83 | expr: expr PLUS term { $$ = $0 + $2; } 84 | expr: expr MINUS term { $$ = $0 - $2; } 85 | 86 | term: factor { $$ = $0; } 87 | term: term ASTERISK factor { $$ = $0 * $2; } 88 | term: term SLASH factor { $$ = $0 / $2; } 89 | 90 | factor: value { $$ = $0; } 91 | factor: MINUS factor { $$ = -$1; } 92 | factor: PAR_OPEN expr PAR_CLOSE { $$ = $1; } 93 | 94 | value: INTEGER { $$ = $0; } 95 | 96 | %% 97 | 98 | extern "C" int t8() { 99 | int rv = -1; 100 | int r; 101 | 102 | const char sum[] = "1+2*-3"; 103 | 104 | struct t8_stack stack; 105 | t8_stack_init(&stack); 106 | 107 | t8_set_input(&stack, sum, sizeof(sum) - 1, 1); 108 | int final_result = 0; 109 | r = t8_scan(&stack, final_result); 110 | if (r != _T8_FINISH) { 111 | rv = -2; 112 | goto fail; 113 | } 114 | if (final_result != -5) { 115 | rv = -3; 116 | goto fail; 117 | } 118 | 119 | /* At this point, the only object that should exist on the stack 120 | * is the grammar object; all value objects should be cleaned up. */ 121 | if (Value::open_value_count_ > 0) { 122 | rv = -4; 123 | goto fail; 124 | } 125 | if (GrammarObj::open_grammar_count_ != 1) { 126 | rv = -5; 127 | goto fail; 128 | } 129 | 130 | /* Resetting the stack should clear out the only object on the stack, 131 | * being, the grammar object. */ 132 | t8_stack_reset(&stack); 133 | 134 | if (GrammarObj::open_grammar_count_ > 0) { 135 | rv = -6; 136 | goto fail; 137 | } 138 | rv = 0; 139 | 140 | fail: 141 | t8_stack_cleanup(&stack); 142 | return rv; 143 | } 144 | 145 | -------------------------------------------------------------------------------- /tester/t1.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | %scanner% 20 | %prefix t1_ 21 | 22 | INTEGER: [0-9]+ { $$ = atoi($text); } 23 | 24 | : [\ \n]+; /* skip spaces and newlines */ 25 | PLUS: \+; 26 | MINUS: \-; 27 | ASTERISK: \*; 28 | SLASH: /; 29 | PAR_OPEN: \(; 30 | PAR_CLOSE: \); 31 | 32 | %token PLUS MINUS ASTERISK SLASH PAR_OPEN PAR_CLOSE INTEGER 33 | %nt grammar expr term factor value 34 | 35 | %grammar% 36 | 37 | %type grammar expr term factor value INTEGER: int 38 | %constructor $$ = 0; 39 | %destructor /* destructing */ $$ = 0; 40 | 41 | %common_type int 42 | %destructor /* destructing common */ $$ = 0; 43 | 44 | %params int *final_result 45 | 46 | grammar: expr { 47 | *final_result = $0; 48 | } 49 | 50 | expr: term { $$ = $0; } 51 | expr: expr PLUS term { $$ = $0 + $2; } 52 | expr: expr MINUS term { $$ = $0 - $2; } 53 | 54 | term: factor { $$ = $0; } 55 | term: term ASTERISK factor { $$ = $0 * $2; } 56 | term: term SLASH factor { $$ = $0 / $2; } 57 | 58 | factor: value { $$ = $0; } 59 | factor: MINUS factor { $$ = -$1; } 60 | factor: PAR_OPEN expr PAR_CLOSE { $$ = $1; } 61 | 62 | value: INTEGER { $$ = $0; } 63 | 64 | value: error { $$ = 0; } 65 | 66 | %% 67 | 68 | int t1(void) { 69 | struct t1_stack stack; 70 | t1_stack_init(&stack); 71 | const char sum[] = "1+2*-3"; 72 | t1_set_input(&stack, sum, sizeof(sum)-1, 1); 73 | int r; 74 | int final_result; 75 | r = t1_scan(&stack, &final_result); 76 | 77 | t1_stack_cleanup(&stack); 78 | 79 | if (r != _T1_FINISH) return -1; 80 | if (final_result != -5) return -1; 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /tester/t2.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | %scanner% 20 | %prefix t2_ 21 | 22 | : [\ \n]+; /* skip spaces and newlines */ 23 | PAR_OPEN: \(; 24 | PAR_CLOSE: \); 25 | 26 | %token PAR_OPEN PAR_CLOSE 27 | %nt term 28 | 29 | %grammar% 30 | 31 | term: PAR_OPEN term PAR_CLOSE; 32 | term: ; 33 | 34 | %% 35 | 36 | int t2(void) { 37 | int rv = -1; 38 | int r; 39 | struct t2_stack stack; 40 | t2_stack_init(&stack); 41 | const char paired[] = "((()))"; 42 | t2_set_input(&stack, paired, sizeof(paired)-1, 1); 43 | r = t2_scan(&stack); 44 | 45 | if (r != _T2_FINISH) goto fail; 46 | 47 | const char mismatched[] = "())"; 48 | t2_set_input(&stack, mismatched, sizeof(mismatched) - 1, 1); 49 | r = t2_scan(&stack); 50 | 51 | if (r != _T2_SYNTAX_ERROR) goto fail; 52 | 53 | rv = 0; 54 | fail: 55 | t2_stack_cleanup(&stack); 56 | return rv; 57 | } 58 | -------------------------------------------------------------------------------- /tester/t3.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | %scanner% 20 | %prefix t3_ 21 | 22 | %params int *times 23 | 24 | /* Single dot anychar */ 25 | : . { (*times)++; } 26 | 27 | %% 28 | 29 | int t3(void) { 30 | /* NOTE: Should be compiled without UTF-8 mode on carburetta; otherwise it fails on CR/NEL */ 31 | int rv = -1; 32 | int r; 33 | struct t3_stack stack; 34 | t3_stack_init(&stack); 35 | int times; 36 | const char single_x[] = "x"; 37 | t3_set_input(&stack, single_x, sizeof(single_x)-1, 1); 38 | times = 0; 39 | r = t3_scan(&stack, ×); 40 | 41 | if (r != _T3_FINISH) goto fail; 42 | if (times != 1) goto fail; 43 | 44 | const char double_x[] = "xx"; 45 | t3_set_input(&stack, double_x, sizeof(double_x) - 1, 1); 46 | times = 0; 47 | r = t3_scan(&stack, ×); 48 | 49 | if (r != _T3_FINISH) goto fail; 50 | if (times != 2) goto fail; 51 | 52 | 53 | const char no_newline[] = "x\nx"; 54 | t3_set_input(&stack, no_newline, sizeof(no_newline) - 1, 1); 55 | times = 0; 56 | r = t3_scan(&stack, ×); 57 | if (r != _T3_LEXICAL_ERROR) goto fail; 58 | if (times != 1) goto fail; /* only one dot (the first x) should have matched */ 59 | 60 | uint8_t all_the_chars; 61 | int n; 62 | for (n = 0; n < 256; ++n) { 63 | all_the_chars = (uint8_t)n; 64 | t3_set_input(&stack, (const char *)&all_the_chars, 1, 1); 65 | times = 0; 66 | r = t3_scan(&stack, ×); 67 | if (r == _T3_LEXICAL_ERROR) { 68 | /* Raw / Latin-1 decoder is fairly pedantic, the UTF-8 one, due to being complex, only does the bare minimum (LF). 69 | * So here we check for all LF, CR and NEL. */ 70 | if ((n != 0xA) && (n != 0xD) && (n != 0x85 /* NEL */)) { 71 | fprintf(stderr, "Unexpected lexical error on latin-1 (raw) character 0x%02X\n", n); 72 | goto fail; 73 | } 74 | /* Newline is expected to fail */ 75 | } 76 | else if ((r == _T3_FINISH) && (n == 0xD)) { 77 | fprintf(stderr, "Latin-1 (raw) encoder does not accept CR as newline, is t3 incorrectly compiled for UTF-8?\n"); 78 | goto fail; 79 | } 80 | else if ((r == _T3_FINISH) && (n == 0x85)) { 81 | fprintf(stderr, "Latin-1 (raw) encoder does not accept NEL (U+0085 NEXT LINE) as newline, is t3 incorrectly compiled for UTF-8?\n"); 82 | goto fail; 83 | } 84 | else if (r != _T3_FINISH) { 85 | goto fail; 86 | } 87 | else if (times != 1) goto fail; 88 | } 89 | 90 | rv = 0; 91 | fail: 92 | t3_stack_cleanup(&stack); 93 | return rv; 94 | } 95 | -------------------------------------------------------------------------------- /tester/t4.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | /* little helper function defined in tester.c, to read UTF-8 as a codepoint value.. */ 21 | int get_next_utf8_codepoint(const char **pputf8); 22 | 23 | /* little helper function to encode a UTF-8 codepoint as a string. */ 24 | int codepoint_as_utf8(char *dst, uint32_t codepoint); 25 | 26 | %scanner% 27 | %prefix t4_ 28 | %params int unicode_value 29 | 30 | /* Single dot anychar */ 31 | : . { 32 | /* Check that the thing we matched is infact the unicode codepoint expected. */ 33 | const char *cp = $text; 34 | if (get_next_utf8_codepoint(&cp) != unicode_value) return -1; 35 | if (cp != $text + $len) return -2; 36 | } 37 | 38 | %% 39 | 40 | int t4(void) { 41 | int rv = -1; 42 | int r; 43 | struct t4_stack stack; 44 | t4_stack_init(&stack); 45 | char cp_utf8[4]; 46 | 47 | int found_0xA, found_0xD, found_0x85 /* NEL */, found_0x2028 /* LS */; 48 | 49 | found_0xA = found_0xD = found_0x85 = found_0x2028 = 0; 50 | 51 | uint32_t cp; 52 | for (cp = 0x0; cp < 0x10FFFF; ++cp) { 53 | t4_set_input(&stack, cp_utf8, codepoint_as_utf8(cp_utf8, cp), 1); 54 | r = t4_scan(&stack, cp); 55 | if (r == -1) { 56 | /* Codepoint mismatched */ 57 | fprintf(stderr, "Codepoint 0x%0X mismatched\n", cp); 58 | 59 | rv = -1; 60 | goto fail; 61 | } 62 | if (r == -2) { 63 | /* Length mismatched */ 64 | rv = -2; 65 | goto fail; 66 | } 67 | if (r == _T4_LEXICAL_ERROR) { 68 | /* Failing to match the dot anychar is fine, provided the codepoint is a newline. */ 69 | if (cp == 0xA) { found_0xA = 1; } 70 | else if (cp == 0xD) { found_0xD = 1; } 71 | else if (cp == 0x85) { found_0x85 = 1; } 72 | else if (cp == 0x2028) { found_0x2028 = 1; } 73 | else { 74 | fprintf(stderr, "Lexical error on codepoint 0x%X\n", cp); 75 | rv = -3; 76 | goto fail; 77 | } 78 | } 79 | else if (r != _T4_FINISH) { 80 | rv = -4; 81 | goto fail; 82 | } 83 | } 84 | if (!found_0xA) { 85 | fprintf(stderr, "Dot unexpectedly matched on 0xA\n"); 86 | rv = -5; 87 | goto fail; 88 | } 89 | if (!found_0xD) { 90 | fprintf(stderr, "Dot unexpectedly matched on 0xD\n"); 91 | rv = -6; 92 | goto fail; 93 | } 94 | if (!found_0x85) { 95 | fprintf(stderr, "Dot unexpectedly matched on 0x85\n"); 96 | rv = -7; 97 | goto fail; 98 | } 99 | if (!found_0x2028) { 100 | fprintf(stderr, "Dot unexpectedly matched on 0x2028\n"); 101 | rv = -8; 102 | goto fail; 103 | } 104 | 105 | rv = 0; 106 | fail: 107 | t4_stack_cleanup(&stack); 108 | return rv; 109 | } 110 | -------------------------------------------------------------------------------- /tester/t5.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | /* little helper function defined below, to read UTF-8 as a codepoint value.. */ 21 | int get_next_utf8_codepoint(const char **pputf8); 22 | 23 | /* little helper function to encode a UTF-8 codepoint as a string. */ 24 | int codepoint_as_utf8(char *dst, uint32_t codepoint); 25 | 26 | static int which_range(uint32_t cp) { 27 | /* See below, these are the ranges we'd like to catch. */ 28 | if ((cp >= 0x5000) && (cp <= 0xC000)) return 5; 29 | if ((cp >= 0x4000) && (cp <= 0xD000)) return 4; 30 | if ((cp >= 0x3000) && (cp <= 0xE000)) return 3; 31 | if ((cp >= 0x2000) && (cp <= 0xF000)) return 2; 32 | if ((cp >= 0x1000) && (cp <= 0x100000)) return 1; 33 | return 0; 34 | } 35 | 36 | %scanner% 37 | %prefix t5_ 38 | %params int unicode_value 39 | 40 | /* Overlapping character set ranges - first one that matches gets the action, so 41 | * start with the narrowest range and expand to a catch all */ 42 | : [\u{5000}-\u{C000}] { 43 | const char *cp = $text; 44 | if (which_range(get_next_utf8_codepoint(&cp)) != 5) return -1; 45 | } 46 | : [\u{4000}-\u{D000}] { 47 | const char *cp = $text; 48 | if (which_range(get_next_utf8_codepoint(&cp)) != 4) return -1; 49 | } 50 | : [\u{3000}-\u{E000}] { 51 | const char *cp = $text; 52 | if (which_range(get_next_utf8_codepoint(&cp)) != 3) return -1; 53 | } 54 | : [\u{2000}-\u{F000}] { 55 | const char *cp = $text; 56 | if (which_range(get_next_utf8_codepoint(&cp)) != 2) return -1; 57 | } 58 | : [\u{1000}-\u{100000}] { 59 | const char *cp = $text; 60 | if (which_range(get_next_utf8_codepoint(&cp)) != 1) return -1; 61 | } 62 | : [\u{0000}-\u{10FFFF}] { 63 | const char *cp = $text; 64 | if (which_range(get_next_utf8_codepoint(&cp)) != 0) return -1; 65 | } 66 | 67 | : . { 68 | /* Range fully captured by [\u{0000}-\u{10FFFF}] so should not match */ 69 | return -1; 70 | } 71 | 72 | %% 73 | 74 | int t5(void) { 75 | int rv = -1; 76 | int r; 77 | struct t5_stack stack; 78 | t5_stack_init(&stack); 79 | char cp_utf8[4]; 80 | 81 | uint32_t cp; 82 | for (cp = 0x0; cp < 0x10FFFF; ++cp) { 83 | t5_set_input(&stack, cp_utf8, codepoint_as_utf8(cp_utf8, cp), 1); 84 | r = t5_scan(&stack, cp); 85 | if (r == -1) { 86 | /* Codepoint mismatched */ 87 | fprintf(stderr, "Codepoint 0x%0X mismatched\n", cp); 88 | 89 | rv = -1; 90 | goto fail; 91 | } 92 | if (r != _T5_FINISH) { 93 | rv = -4; 94 | goto fail; 95 | } 96 | } 97 | 98 | rv = 0; 99 | fail: 100 | t5_stack_cleanup(&stack); 101 | return rv; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /tester/t6.cbrt: -------------------------------------------------------------------------------- 1 | /* Copyright 2020-2025 Kinglet B.V. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | %scanner% 22 | %prefix t6_ 23 | 24 | %% 25 | static int num_letters_ = 0; 26 | static int num_spaces_ = 0; 27 | static int num_punctuation_ = 0; 28 | static char msg_[] = "\"Voila\xCC\x80,\" I said, as I handed my Re\xCC\x81sume\xCC\x81 over to the Paparazzo\xCC\x80 over a Pin\xCC\x83""a colada flavored Cre\xCC\x80me bru\xCC\x82le\xCC\x81""e at the ho\xCC\x82tel cafe\xCC\x81."; 29 | static char bland_msg_[] = "\"Voila,\" I said, as I handed my Resume over to the Paparazzo over a Pina colada flavored Creme brulee at the hotel cafe."; 30 | static int bleached_msg_len_ = 0; 31 | static char bleached_msg_[sizeof(msg_) + 1] = {0}; 32 | %% 33 | 34 | : (\p{Letter}\p{Nonspacing_Mark}*) { 35 | /* Letters including diacretics */ 36 | num_letters_++; 37 | if (bleached_msg_len_ == sizeof(msg_)) return -1; 38 | bleached_msg_[bleached_msg_len_++] = *$text; 39 | } 40 | 41 | : \p{Space_Separator} { 42 | /* Spaces */ 43 | num_spaces_++; 44 | if (bleached_msg_len_ == sizeof(msg_)) return -1; 45 | bleached_msg_[bleached_msg_len_++] = *$text; 46 | } 47 | 48 | : \p{Other_Punctuation} { 49 | /* Punctuation */ 50 | num_punctuation_++; 51 | if (bleached_msg_len_ == sizeof(msg_)) return -1; 52 | bleached_msg_[bleached_msg_len_++] = *$text; 53 | } 54 | 55 | : . { 56 | /* Range fully captured so should not match */ 57 | return -1; 58 | } 59 | 60 | %% 61 | 62 | int t6(void) { 63 | int rv = -1; 64 | int r; 65 | struct t6_stack stack; 66 | t6_stack_init(&stack); 67 | 68 | t6_set_input(&stack, msg_, sizeof(msg_)-1, 1); 69 | r = t6_scan(&stack); 70 | if (r == -1) { 71 | /* Codepoint mismatched */ 72 | rv = -1; 73 | goto fail; 74 | } 75 | if (r != _T6_FINISH) { 76 | rv = -2; 77 | goto fail; 78 | } 79 | if (bleached_msg_len_ == sizeof(msg_)) { 80 | /* Message should not exceed buffer. */ 81 | rv = -3; 82 | goto fail; 83 | } 84 | bleached_msg_[bleached_msg_len_++] = 0; 85 | 86 | /* Terminate. */ 87 | if (strcmp(bleached_msg_, bland_msg_)) { 88 | /* Bleached message should be msg_ without diacritics; but otherwise the same - unfortunately it's not. */ 89 | rv = -4; 90 | goto fail; 91 | } 92 | 93 | if (num_letters_ != 93) { 94 | rv = -5; 95 | goto fail; 96 | } 97 | 98 | if (num_spaces_ != 22) { 99 | rv = -6; 100 | goto fail; 101 | } 102 | 103 | if (num_punctuation_ != 5) { 104 | rv = -7; 105 | goto fail; 106 | } 107 | 108 | rv = 0; 109 | fail: 110 | t6_stack_cleanup(&stack); 111 | return rv; 112 | } 113 | 114 | --------------------------------------------------------------------------------