From dee5b8dfb5752a7371058566adc50bbedbe38524 Mon Sep 17 00:00:00 2001 From: Creeper Lv Date: Tue, 26 May 2026 16:59:39 +1000 Subject: [PATCH] Initial Commit. --- .gitignore | 3 + Headers/scc_core.h | 62 +++++++++ README.md | 176 +++++++++++++++++++++++++ Source/Languages/C/scc_template.c | 6 + Source/Languages/CSharp/scc_template.c | 6 + Source/cli/main.c | 7 + Source/scc.c | 6 + build.sh | 20 +++ 8 files changed, 286 insertions(+) create mode 100644 .gitignore create mode 100644 Headers/scc_core.h create mode 100644 README.md create mode 100644 Source/Languages/C/scc_template.c create mode 100644 Source/Languages/CSharp/scc_template.c create mode 100644 Source/cli/main.c create mode 100644 Source/scc.c create mode 100644 build.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dff9d52 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bin/ +env.sh +.vscode/ diff --git a/Headers/scc_core.h b/Headers/scc_core.h new file mode 100644 index 0000000..540b622 --- /dev/null +++ b/Headers/scc_core.h @@ -0,0 +1,62 @@ +#ifndef __SCC_CORE_H_ +#define __SCC_CORE_H_ +#include +#include +#include +typedef enum scc_target_language +{ + c_language, + csharp, +} scc_target_language; +typedef struct scc_options +{ + scc_target_language target_language; + char *header_output; + char *namespace_name; + char *class_name; + char *prefix; + char *data_type_name; + char *slex_namespace_name; + char *slex_class_name; + char *slex_prefix; + char *slex_data_type_name; +} scc_options; + +typedef struct scc_matching +{ + char **match_ids; + uint64_t match_ids; + char *target_syntax_id; + char **using_match_id; + uint64_t using_match_id_count; +} scc_matching; + +typedef struct scc_rule +{ + char *node_type_name; + scc_matching **matchings; + uint64_t matching_count; +} scc_rule; +typedef struct code_block +{ + scc_target_language target_languge; + char *post_processor_code; + char *variables; +} code_block; + +typedef struct scc_rules +{ + scc_rule *rules; + uint64_t rule_count; + char **syntax_ids; + uint64_t syntax_id_count; +} scc_rules; + +bool scc_read_rule_from_file(FILE *f, scc_rules *output_rule); +bool scc_read_rule_from_cstr(char *content, scc_rules *output_rule); + +bool scc_translate_to_file_c(scc_options *options, scc_rules *rules, FILE *output_file); +bool scc_translate_to_file_csharp(scc_options *options, scc_rules *rules, FILE *output_file); +bool scc_translate_to_file(scc_options *options, scc_rules *rules, FILE *output_file); + +#endif \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0724d1b --- /dev/null +++ b/README.md @@ -0,0 +1,176 @@ +# SCC + +Simple Compiler-Compiler. This program is designed to generate a parser that builds a syntax tree using a rule file with `slex` lexer. + +Currently, this project aims on supporting following target platform/languages: + +|Language| Version| Platform| +|--------|--------|--------- | +|C | 99 | Win32, POSIX, ESP32 | +|C# | 9.0 | .netstandard2.1(all possible target platform, including Unity)| + +## SCC Rule format + +``` +syntax_ids: + + +... + +rules: + +node_type +: [node_type/slex_id/slex_tag/direct_string] [node_type/slex_id/slex_tag/direct_string] ... +=> [operation] $0 $1 ... +: [node_type/slex_id/slex_tag/direct_string] [node_type/slex_id/slex_tag/direct_string] ... +=> [operation] $0 $1 ... +; + +# +# $0 and $1 here means selected node/segment from matching element list. +# + +``` + + +### Operations + +- `new_node `: create a new node and attach to parent node +- `append_as_child`: append selected +- `skip`: do nothing + +### Sample: + +``` + +syntax_ids: + +binary_expr +function_call_expr +argument_list +variable + +rules: + +expr +: expr binary_operator expr +=> new_node binary_expr $0 $1 $2 +: name "(" argument_list ")" +=> new_node function_call_expr $0 +| name +=> new_node variable $0 +; + +argument_list +:argument_list "," expr +=> append_as_child $2 +:expr +=> new_node argument_list $0 +; +``` + +## Usage + +``` +scc [options] [options] + +input file usually ends with `.scc` + +Options: + +-o output file/output folder +-l specify target language, e.g: c, c#, csharp +-h
output header file (will separate output implementation and definitions when language is c or c++. Note: c++ is currently not supported.) +-ns specify namespace (supported languages only). Default is `scc_generated`, `SCCGenerated`, `io.creeperlv.scc.generated` for applicable language. +-class specify class name (supported languages only). Default is `scc`, `SCC`. +-prefix specify prefix for functions. Default is `scc_` for languages does not support namespace/class, `` (empty string) for languages support namespace/class. +-data_type specify the name of the syntax node data type. +-slex-ns specify namespace used in slex. +-slex-class specify class name used in slex. +-slex-prefix specify function prefix used in slex. +-slex-data_type specify segment data type used in slex. +``` + +### Data Type Name Table + +|Language | Type Name | +| ------- | ---------------- | +| C | scc_syntax_node | +| C# | SyntaxNode | + +### Generated parser + +All usages here uses default settings + +#### C99 + + +Usage sample: +``` +void scc_sample(FILE* f, char* file_name){ + + struct slex_segment* head; + const char* str=""; + if(slex_file(f, file_name, &head)){ + //Success + struct scc_syntax_node* root; + if(scc_parse(head,&root)){ + //Success + } + } + slex_free(head); +} +``` + +API and defined data types: +```c +typedef struct scc_syntax_node_enclosure{ + enum scc_syntax_node_type; + void* data; +}scc_syntax_node_enclosure; +typedef enum scc_syntax_node_type{ + scc_node, scc_segment +}scc_syntax_node_type; +typedef struct scc_syntax_node{ + enum scc_syntax_id; + char* syntax_name; + scc_syntax_node_enclosure* children; + uint64_t child_count; + scc_syntax_node* parent; +} scc_syntax_node; + +typedef enum scc_syntax_id{ + default, +}scc_syntax_id; +char scc_parse(slex_segment* head, scc_syntax_node** output); +char scc_free(scc_syntax_node* root); +``` + +#### C# +##### APIs: +``` +using SLexGenerated; +namesapce SCCGenerated{ + public class SCC{ + public bool Parse(Segment head, out SyntaxNode Root); + } + + public enum SyntaxId{ + Default, + } + public class SyntaxNodeEnclosure{ + public SyntaxNode? Node; + public Segment? Segment; + public EnclosureType EnclosureType; + } + public enum EnclosureType{ + Node, Segment + } + public class SyntaxNode{ + public SyntaxNode? Parent; + public string SyntaxName; + public SyntaxId Id; + public List Children; + } +} +``` diff --git a/Source/Languages/C/scc_template.c b/Source/Languages/C/scc_template.c new file mode 100644 index 0000000..fd65416 --- /dev/null +++ b/Source/Languages/C/scc_template.c @@ -0,0 +1,6 @@ +#include "../../../Headers/scc_core.h" + +bool scc_translate_to_file_c(scc_options *options, scc_rules *rules, FILE *output_file){ + //Stub for now. + return false; +} \ No newline at end of file diff --git a/Source/Languages/CSharp/scc_template.c b/Source/Languages/CSharp/scc_template.c new file mode 100644 index 0000000..d6e3902 --- /dev/null +++ b/Source/Languages/CSharp/scc_template.c @@ -0,0 +1,6 @@ +#include "../../../Headers/scc_core.h" + +bool scc_translate_to_file_csharp(scc_options *options, scc_rules *rules, FILE *output_file){ + //Stub for now. + return false; +} \ No newline at end of file diff --git a/Source/cli/main.c b/Source/cli/main.c new file mode 100644 index 0000000..7c806ee --- /dev/null +++ b/Source/cli/main.c @@ -0,0 +1,7 @@ +#include "../../Headers/scc_core.h" + +int main(int ac, char **av) +{ + + return 0; +} \ No newline at end of file diff --git a/Source/scc.c b/Source/scc.c new file mode 100644 index 0000000..cc49b62 --- /dev/null +++ b/Source/scc.c @@ -0,0 +1,6 @@ +#include "../Headers/scc_core.h" + +bool scc_translate_to_file(scc_options *options, scc_rules *rules, FILE *output_file){ + //Stub for now. + return false; +} \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..faef3b3 --- /dev/null +++ b/build.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +mkdir -p ./bin/ + +if [ -f "./env.sh" ]; +then + source ./env.sh +fi + +if [ -z "$CC" ]; +then + CC=cc +fi + +if [ -z "$SKIP_EXE" ]; +then + COMMAND="$CC ./Source/*.c ./Source/cli/*.c ./Source/Languages/*/*.c -o ./bin/scc" + echo "$COMMAND" + $COMMAND +fi