proper implementation in C
This commit is contained in:
parent
475d2976d9
commit
b2912528bd
27
Makefile
27
Makefile
@ -1,9 +1,24 @@
|
|||||||
.PHONY: main test
|
.PHONY: main test
|
||||||
|
|
||||||
main:
|
CFLAGS := -std=c2x -Wall -Wpedantic
|
||||||
g++ source/tbc.cpp $$(pkg-config --cflags --libs tree-sitter tree-sitter-c) -ggdb
|
|
||||||
|
|
||||||
test:
|
ifeq (${DEBUG}, 1)
|
||||||
python source/tbc.py test/convert.tbsp > object/kek.cpp
|
LFLAGS += --debug --trace
|
||||||
bake object/kek.cpp
|
YFLAGS += --debug
|
||||||
./object/a.out test/input.md
|
CFLAGS += -O0 -ggdb -fno-inline
|
||||||
|
CPPFLAGS += -DDEBUG
|
||||||
|
else
|
||||||
|
CFLAGS += -O3 -flto=auto -fno-stack-protector
|
||||||
|
endif
|
||||||
|
|
||||||
|
OUT := tbsp
|
||||||
|
|
||||||
|
main:
|
||||||
|
bison ${YFLAGS} --header=object/tbsp.tab.h -o object/tbsp.tab.c source/tbsp.y
|
||||||
|
flex ${LFLAGS} --header-file=object/tbsp.yy.h -o object/tbsp.yy.c source/tbsp.l
|
||||||
|
gcc ${CPPFLAGS} ${CFLAGS} -Iobject -Ilibrary object/tbsp.tab.c object/tbsp.yy.c source/tbsp.c library/sds.c -o ${OUT}
|
||||||
|
|
||||||
|
run:
|
||||||
|
./${OUT} test/convert.tbsp > object/test.cpp
|
||||||
|
bake object/test.cpp
|
||||||
|
./object/test.out test/input.md
|
||||||
|
90
library/kvec.h
Normal file
90
library/kvec.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/* The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2008, by Attractive Chaos <attractor@live.co.uk>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
An example:
|
||||||
|
|
||||||
|
#include "kvec.h"
|
||||||
|
int main() {
|
||||||
|
kvec_t(int) array;
|
||||||
|
kv_init(array);
|
||||||
|
kv_push(int, array, 10); // append
|
||||||
|
kv_a(int, array, 20) = 5; // dynamic
|
||||||
|
kv_A(array, 20) = 4; // static
|
||||||
|
kv_destroy(array);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
2008-09-22 (0.1.0):
|
||||||
|
|
||||||
|
* The initial version.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AC_KVEC_H
|
||||||
|
#define AC_KVEC_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
|
||||||
|
|
||||||
|
#define kvec_t(type) struct { size_t n, m; type *a; }
|
||||||
|
#define kv_init(v) ((v).n = (v).m = 0, (v).a = 0)
|
||||||
|
#define kv_destroy(v) free((v).a)
|
||||||
|
#define kv_A(v, i) ((v).a[(i)])
|
||||||
|
#define kv_pop(v) ((v).a[--(v).n])
|
||||||
|
#define kv_size(v) ((v).n)
|
||||||
|
#define kv_max(v) ((v).m)
|
||||||
|
|
||||||
|
#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
|
||||||
|
|
||||||
|
#define kv_copy(type, v1, v0) do { \
|
||||||
|
if ((v1).m < (v0).n) kv_resize(type, v1, (v0).n); \
|
||||||
|
(v1).n = (v0).n; \
|
||||||
|
memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \
|
||||||
|
} while (0) \
|
||||||
|
|
||||||
|
#define kv_push(type, v, x) do { \
|
||||||
|
if ((v).n == (v).m) { \
|
||||||
|
(v).m = (v).m? (v).m<<1 : 2; \
|
||||||
|
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m); \
|
||||||
|
} \
|
||||||
|
(v).a[(v).n++] = (x); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define kv_pushp(type, v) (((v).n == (v).m)? \
|
||||||
|
((v).m = ((v).m? (v).m<<1 : 2), \
|
||||||
|
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \
|
||||||
|
: 0), ((v).a + ((v).n++))
|
||||||
|
|
||||||
|
#define kv_a(type, v, i) (((v).m <= (size_t)(i)? \
|
||||||
|
((v).m = (v).n = (i) + 1, kv_roundup32((v).m), \
|
||||||
|
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \
|
||||||
|
: (v).n <= (size_t)(i)? (v).n = (i) + 1 \
|
||||||
|
: 0), (v).a[(i)])
|
||||||
|
|
||||||
|
#endif
|
1603
library/sds.c
Normal file
1603
library/sds.c
Normal file
File diff suppressed because it is too large
Load Diff
155
library/sds.h
Normal file
155
library/sds.h
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/* SDSLib 2.3 -- A C dynamic strings library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||||
|
* Copyright (c) 2015, Oran Agra
|
||||||
|
* Copyright (c) 2015, Redis Labs, Inc
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Redis nor the names of its contributors may be used
|
||||||
|
* to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SDS_H
|
||||||
|
#define __SDS_H
|
||||||
|
|
||||||
|
#define SDS_MAX_PREALLOC (1024*1024)
|
||||||
|
extern const char *SDS_NOINIT;
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef char *sds;
|
||||||
|
|
||||||
|
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
||||||
|
* However is here to document the layout of type 5 SDS strings. */
|
||||||
|
struct __attribute__ ((__packed__)) sdshdr5 {
|
||||||
|
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
||||||
|
char buf[];
|
||||||
|
};
|
||||||
|
struct __attribute__ ((__packed__)) sdshdr8 {
|
||||||
|
uint8_t len; /* used */
|
||||||
|
uint8_t alloc; /* excluding the header and null terminator */
|
||||||
|
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||||
|
char buf[];
|
||||||
|
};
|
||||||
|
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||||
|
uint16_t len; /* used */
|
||||||
|
uint16_t alloc; /* excluding the header and null terminator */
|
||||||
|
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||||
|
char buf[];
|
||||||
|
};
|
||||||
|
struct __attribute__ ((__packed__)) sdshdr32 {
|
||||||
|
uint32_t len; /* used */
|
||||||
|
uint32_t alloc; /* excluding the header and null terminator */
|
||||||
|
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||||
|
char buf[];
|
||||||
|
};
|
||||||
|
struct __attribute__ ((__packed__)) sdshdr64 {
|
||||||
|
uint64_t len; /* used */
|
||||||
|
uint64_t alloc; /* excluding the header and null terminator */
|
||||||
|
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||||
|
char buf[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SDS_TYPE_5 0
|
||||||
|
#define SDS_TYPE_8 1
|
||||||
|
#define SDS_TYPE_16 2
|
||||||
|
#define SDS_TYPE_32 3
|
||||||
|
#define SDS_TYPE_64 4
|
||||||
|
#define SDS_TYPE_MASK 7
|
||||||
|
#define SDS_TYPE_BITS 3
|
||||||
|
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
|
||||||
|
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||||
|
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||||
|
|
||||||
|
size_t sdslen(const sds s);
|
||||||
|
size_t sdsavail(const sds s);
|
||||||
|
void sdssetlen(sds s, size_t newlen);
|
||||||
|
void sdsinclen(sds s, size_t inc);
|
||||||
|
size_t sdsalloc(const sds s);
|
||||||
|
void sdssetalloc(sds s, size_t newlen);
|
||||||
|
|
||||||
|
sds sdsnewlen(const void *init, size_t initlen);
|
||||||
|
sds sdsnew(const char *init);
|
||||||
|
sds sdsempty(void);
|
||||||
|
sds sdsdup(const sds s);
|
||||||
|
void sdsfree(sds s);
|
||||||
|
sds sdsgrowzero(sds s, size_t len);
|
||||||
|
sds sdscatlen(sds s, const void *t, size_t len);
|
||||||
|
sds sdscat(sds s, const char *t);
|
||||||
|
sds sdscatsds(sds s, const sds t);
|
||||||
|
sds sdscpylen(sds s, const char *t, size_t len);
|
||||||
|
sds sdscpy(sds s, const char *t);
|
||||||
|
|
||||||
|
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
|
||||||
|
#ifdef __GNUC__
|
||||||
|
sds sdscatprintf(sds s, const char *fmt, ...)
|
||||||
|
__attribute__((format(printf, 2, 3)));
|
||||||
|
#else
|
||||||
|
sds sdscatprintf(sds s, const char *fmt, ...);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sds sdscatfmt(sds s, char const *fmt, ...);
|
||||||
|
void sdstrim(sds s, const char *cset);
|
||||||
|
void sdssubstr(sds s, size_t start, size_t len);
|
||||||
|
void sdsrange(sds s, ssize_t start, ssize_t end);
|
||||||
|
void sdsupdatelen(sds s);
|
||||||
|
void sdsclear(sds s);
|
||||||
|
int sdscmp(const sds s1, const sds s2);
|
||||||
|
sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count);
|
||||||
|
void sdsfreesplitres(sds *tokens, int count);
|
||||||
|
void sdstolower(sds s);
|
||||||
|
void sdstoupper(sds s);
|
||||||
|
sds sdsfromlonglong(long long value);
|
||||||
|
sds sdscatrepr(sds s, const char *p, size_t len);
|
||||||
|
sds *sdssplitargs(const char *line, int *argc);
|
||||||
|
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
||||||
|
sds sdsjoin(char **argv, int argc, char *sep);
|
||||||
|
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
|
||||||
|
int sdsneedsrepr(const sds s);
|
||||||
|
|
||||||
|
/* Low level functions exposed to the user API */
|
||||||
|
sds sdsMakeRoomFor(sds s, size_t addlen);
|
||||||
|
void sdsIncrLen(sds s, ssize_t incr);
|
||||||
|
sds sdsRemoveFreeSpace(sds s);
|
||||||
|
sds sdsResize(sds s, size_t size);
|
||||||
|
size_t sdsAllocSize(sds s);
|
||||||
|
void *sdsAllocPtr(sds s);
|
||||||
|
|
||||||
|
/* Export the allocator used by SDS to the program using SDS.
|
||||||
|
* Sometimes the program SDS is linked to, may use a different set of
|
||||||
|
* allocators, but may want to allocate or free things that SDS will
|
||||||
|
* respectively free or allocate. */
|
||||||
|
void *sds_malloc(size_t size);
|
||||||
|
void *sds_realloc(void *ptr, size_t size);
|
||||||
|
void sds_free(void *ptr);
|
||||||
|
|
||||||
|
#ifdef REDIS_TEST
|
||||||
|
int sdsTest(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef inline
|
||||||
|
|
||||||
|
#endif
|
47
library/sdsalloc.h
Normal file
47
library/sdsalloc.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/* SDSLib 2.2 -- A C dynamic strings library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||||
|
* Copyright (c) 2015, Oran Agra
|
||||||
|
* Copyright (c) 2015, Redis Labs, Inc
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Redis nor the names of its contributors may be used
|
||||||
|
* to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* SDS allocator selection.
|
||||||
|
*
|
||||||
|
* This file is used in order to change the SDS allocator at compile time.
|
||||||
|
* Just define the following defines to what you want to use. Also add
|
||||||
|
* the include of your alternate allocator if needed (not needed in order
|
||||||
|
* to use the default libc allocator). */
|
||||||
|
|
||||||
|
#ifndef __SDS_ALLOC_H__
|
||||||
|
#define __SDS_ALLOC_H__
|
||||||
|
|
||||||
|
#define s_malloc malloc
|
||||||
|
#define s_realloc realloc
|
||||||
|
#define s_free free
|
||||||
|
|
||||||
|
#endif
|
122
source/TBSP_strings.inc
Normal file
122
source/TBSP_strings.inc
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
const char * const TBSP_header = "\
|
||||||
|
#include <stdio.h>\n\
|
||||||
|
#include <string.h>\n\
|
||||||
|
\n\
|
||||||
|
#include <tree_sitter/api.h>\n\
|
||||||
|
#ifdef __cplusplus\n\
|
||||||
|
extern \"C\" {\n\
|
||||||
|
#endif\n\
|
||||||
|
extern const TSLanguage * tree_sitter_%s(void);\n\
|
||||||
|
#ifdef __cplusplus\n\
|
||||||
|
}\n\
|
||||||
|
#endif\n\
|
||||||
|
const TSLanguage * (*tblanguage_function)(void) = tree_sitter_%s;\n\
|
||||||
|
\n\
|
||||||
|
typedef struct {\n\
|
||||||
|
const char * const string;\n\
|
||||||
|
const int case_number;\n\
|
||||||
|
} tbcase_t;\n\
|
||||||
|
\n\
|
||||||
|
// XXX better search algo\n\
|
||||||
|
int determine_case(const tbcase_t * const ordered_array, const char * const string) {\n\
|
||||||
|
const tbcase_t * c = ordered_array;\n\
|
||||||
|
for (; c->string != NULL; c++) {\n\
|
||||||
|
if (!strcmp(c->string, string)) { break; }\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
return c->case_number;\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
char * tbtext(const char * const code, TSNode node) {\n\
|
||||||
|
int tblen = ts_node_end_byte(node) - ts_node_start_byte(node);\n\
|
||||||
|
char * r = (char *)malloc(sizeof(char) * (tblen + 1));\n\
|
||||||
|
\n\
|
||||||
|
memcpy(r, code + ts_node_start_byte(node), tblen);\n\
|
||||||
|
r[tblen] = '\\0';\n\
|
||||||
|
\n\
|
||||||
|
return r;\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
#define GET_TBTEXT tbtext(code, current_node)\n\
|
||||||
|
";
|
||||||
|
|
||||||
|
const char * const TBSP_case = "\
|
||||||
|
(tbcase_t) { .string = \"%s\", .case_number = %d },\n\
|
||||||
|
";
|
||||||
|
|
||||||
|
const char * const TBSP_traverse_top = "\
|
||||||
|
int tbtraverse(const char * const code) {\n\
|
||||||
|
// init\n\
|
||||||
|
TSParser * parser;\n\
|
||||||
|
TSTree * tree;\n\
|
||||||
|
TSTreeCursor cursor;\n\
|
||||||
|
TSNode current_node;\n\
|
||||||
|
\n\
|
||||||
|
int tb_case;\n\
|
||||||
|
\n\
|
||||||
|
parser = ts_parser_new();\n\
|
||||||
|
\n\
|
||||||
|
ts_parser_set_language(parser, tblanguage_function());\n\
|
||||||
|
\n\
|
||||||
|
tree = ts_parser_parse_string(parser, NULL, code, strlen(code));\n\
|
||||||
|
cursor = ts_tree_cursor_new(ts_tree_root_node(tree));\n\
|
||||||
|
current_node = ts_tree_root_node(tree);\n\
|
||||||
|
\n\
|
||||||
|
const tbcase_t * current_cases = tb_enter_cases;\n\
|
||||||
|
\n\
|
||||||
|
// meat\n\
|
||||||
|
while (true) {\n\
|
||||||
|
current_node = ts_tree_cursor_current_node(&cursor);\n\
|
||||||
|
\n\
|
||||||
|
tb_case = determine_case(current_cases, ts_node_type(current_node));\n\
|
||||||
|
\n\
|
||||||
|
// XXX INJECTION\n\
|
||||||
|
#if defined(TBDEBUG) && TBDEBUG == 1\n\
|
||||||
|
puts(ts_node_string(current_node));\n\
|
||||||
|
#endif\n\
|
||||||
|
switch (tb_case) {\n\
|
||||||
|
";
|
||||||
|
|
||||||
|
const char * const TBSP_traverse_bottom = "\
|
||||||
|
default: { ; } break;\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
if (ts_node_child_count(current_node)\n\
|
||||||
|
&& current_cases == tb_enter_cases) {\n\
|
||||||
|
ts_tree_cursor_goto_first_child(&cursor);\n\
|
||||||
|
continue;\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
logic:\n\
|
||||||
|
if (!ts_node_is_null(ts_node_next_sibling(current_node))) {\n\
|
||||||
|
if (current_cases == tb_enter_cases) {\n\
|
||||||
|
current_cases = tb_leave_cases;\n\
|
||||||
|
continue;\n\
|
||||||
|
} else {\n\
|
||||||
|
ts_tree_cursor_goto_next_sibling(&cursor);\n\
|
||||||
|
current_cases = tb_enter_cases;\n\
|
||||||
|
continue;\n\
|
||||||
|
}\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
if (current_cases == tb_enter_cases) {\n\
|
||||||
|
current_cases = tb_leave_cases;\n\
|
||||||
|
continue;\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
if (ts_tree_cursor_goto_parent(&cursor)) {\n\
|
||||||
|
current_cases = tb_enter_cases;\n\
|
||||||
|
goto logic;\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
break;\n\
|
||||||
|
}\n\
|
||||||
|
\n\
|
||||||
|
// deinit\n\
|
||||||
|
ts_tree_delete(tree);\n\
|
||||||
|
ts_parser_delete(parser);\n\
|
||||||
|
ts_tree_cursor_delete(&cursor);\n\
|
||||||
|
\n\
|
||||||
|
return 0;\n\
|
||||||
|
}\n\
|
||||||
|
";
|
116
source/tbc.c
Normal file
116
source/tbc.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <tree_sitter/api.h>
|
||||||
|
extern const TSLanguage * tree_sitter_c(void);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char * const string;
|
||||||
|
const int case_number;
|
||||||
|
} tbcase_t;
|
||||||
|
|
||||||
|
const tbcase_t tb_enter_cases[] = {
|
||||||
|
(tbcase_t) { .string = "function_definition", .case_number = 1 },
|
||||||
|
(tbcase_t) { .string = "number_literal", .case_number = 2 },
|
||||||
|
(tbcase_t) { .string = NULL, .case_number = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const tbcase_t tb_leave_cases[] = {
|
||||||
|
(tbcase_t) { .string = "function_definition", .case_number = 3 },
|
||||||
|
(tbcase_t) { .string = NULL, .case_number = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
// XXX better search algo
|
||||||
|
int determine_case(const tbcase_t * const ordered_array, const char * const string) {
|
||||||
|
const tbcase_t * c = ordered_array;
|
||||||
|
for (; c->string != NULL; c++) {
|
||||||
|
if (!strcmp(c->string, string)) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return c->case_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * tbtext(const char * const code, TSNode node) {
|
||||||
|
int tblen = ts_node_end_byte(node) - ts_node_start_byte(node);
|
||||||
|
char * r = (char *)malloc(sizeof(char) * (tblen + 1));
|
||||||
|
|
||||||
|
memcpy(r, code + ts_node_start_byte(node), tblen);
|
||||||
|
r[tblen] = '\0';
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GET_TBTEXT tbtext(code, current_node)
|
||||||
|
|
||||||
|
int tbtraverse(const char * const code) {
|
||||||
|
// init
|
||||||
|
TSParser * parser;
|
||||||
|
TSTree * tree;
|
||||||
|
TSTreeCursor cursor;
|
||||||
|
TSNode current_node;
|
||||||
|
|
||||||
|
int tb_case;
|
||||||
|
|
||||||
|
parser = ts_parser_new();
|
||||||
|
|
||||||
|
ts_parser_set_language(parser, tree_sitter_c());
|
||||||
|
|
||||||
|
tree = ts_parser_parse_string(parser, NULL, code, strlen(code));
|
||||||
|
cursor = ts_tree_cursor_new(ts_tree_root_node(tree));
|
||||||
|
current_node = ts_tree_root_node(tree);
|
||||||
|
|
||||||
|
// meat
|
||||||
|
while (true) {
|
||||||
|
current_node = ts_tree_cursor_current_node(&cursor);
|
||||||
|
|
||||||
|
tb_case = determine_case(tb_enter_cases, ts_node_type(current_node));
|
||||||
|
|
||||||
|
// XXX INJECTION
|
||||||
|
eval:
|
||||||
|
switch (tb_case) {
|
||||||
|
case 1: {
|
||||||
|
puts("ack");
|
||||||
|
char * mytbtext = GET_TBTEXT;
|
||||||
|
puts(mytbtext);
|
||||||
|
free(mytbtext);
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
puts("++");
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
puts("^^df");
|
||||||
|
} break;
|
||||||
|
default: { ; } break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ts_tree_cursor_goto_first_child(&cursor)
|
||||||
|
|| ts_tree_cursor_goto_next_sibling(&cursor)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ts_tree_cursor_goto_parent(&cursor)) {
|
||||||
|
current_node = ts_tree_cursor_current_node(&cursor);
|
||||||
|
if (ts_tree_cursor_goto_next_sibling(&cursor)) {
|
||||||
|
tb_case = determine_case(tb_leave_cases, ts_node_type(current_node));
|
||||||
|
goto eval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// deinit
|
||||||
|
ts_tree_delete(tree);
|
||||||
|
ts_parser_delete(parser);
|
||||||
|
ts_tree_cursor_delete(&cursor);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// @BAKE gcc $@ $(pkg-config --cflags --libs tree-sitter tree-sitter-c) -ggdb
|
||||||
|
|
||||||
|
signed main() {
|
||||||
|
tbtraverse("int main() { return 0; }");
|
||||||
|
}
|
||||||
|
|
122
source/tbc.cpp
122
source/tbc.cpp
@ -1,8 +1,33 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
extern "C" {
|
|
||||||
#include <tree_sitter/api.h>
|
#include <tree_sitter/api.h>
|
||||||
extern const TSLanguage * tree_sitter_c(void);
|
extern const TSLanguage * tree_sitter_c(void);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char * const string;
|
||||||
|
const int case_number;
|
||||||
|
} tbcase_t;
|
||||||
|
|
||||||
|
const tbcase_t tb_enter_cases[] = {
|
||||||
|
(tbcase_t) { .string = "function_definition", .case_number = 1 },
|
||||||
|
(tbcase_t) { .string = "number_literal", .case_number = 2 },
|
||||||
|
(tbcase_t) { .string = NULL, .case_number = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const tbcase_t tb_leave_cases[] = {
|
||||||
|
(tbcase_t) { .string = "function_definition", .case_number = 3 },
|
||||||
|
(tbcase_t) { .string = NULL, .case_number = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
// XXX better search algo
|
||||||
|
int determine_case(tbcase_t * ordered_array, const char * const string) {
|
||||||
|
tbcase_t * c;
|
||||||
|
for (; c->string != NULL; c++) {
|
||||||
|
if (!strcmp(c->string, string)) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return c->case_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tbtraverse(const char * const code) {
|
int tbtraverse(const char * const code) {
|
||||||
@ -13,6 +38,8 @@ int tbtraverse(const char * const code) {
|
|||||||
TSNode current_node;
|
TSNode current_node;
|
||||||
TSNode previous_node;
|
TSNode previous_node;
|
||||||
|
|
||||||
|
int tb_case;
|
||||||
|
|
||||||
parser = ts_parser_new();
|
parser = ts_parser_new();
|
||||||
|
|
||||||
ts_parser_set_language(parser, tree_sitter_c());
|
ts_parser_set_language(parser, tree_sitter_c());
|
||||||
@ -22,71 +49,51 @@ int tbtraverse(const char * const code) {
|
|||||||
current_node = ts_tree_root_node(tree);
|
current_node = ts_tree_root_node(tree);
|
||||||
|
|
||||||
// meat
|
// meat
|
||||||
do {
|
while (true) {
|
||||||
current_node = ts_tree_cursor_current_node(&cursor);
|
current_node = ts_tree_cursor_current_node(&cursor);
|
||||||
|
|
||||||
const char * previous_node_type = NULL;
|
|
||||||
|
|
||||||
int tblen = ts_node_end_byte(current_node) - ts_node_start_byte(current_node);
|
int tblen = ts_node_end_byte(current_node) - ts_node_start_byte(current_node);
|
||||||
char * tbtext = (char *)malloc(sizeof(char) * (tblen + 1));
|
char * tbtext = (char *)malloc(sizeof(char) * (tblen + 1));
|
||||||
memcpy(tbtext, code + ts_node_start_byte(current_node), tblen);
|
memcpy(tbtext, code + ts_node_start_byte(current_node), tblen);
|
||||||
tbtext[tblen] = '\0';
|
tbtext[tblen] = '\0';
|
||||||
|
|
||||||
|
tb_case = determine_case(tb_enter_cases, ts_node_type(current_node));
|
||||||
|
|
||||||
// XXX INJECTION
|
// XXX INJECTION
|
||||||
|
eval:
|
||||||
if (!strcmp("function_definition", ts_node_type(current_node))) {
|
switch (tb_case) {
|
||||||
|
case 1: {
|
||||||
puts("ack");
|
puts("ack");
|
||||||
puts(tbtext);
|
puts(tbtext);
|
||||||
|
} break;
|
||||||
goto end;
|
case 2: {
|
||||||
}
|
puts("++");
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
if (!strcmp("number_literal", ts_node_type(current_node))) {
|
|
||||||
|
|
||||||
puts("++");
|
|
||||||
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end:
|
|
||||||
free(tbtext);
|
|
||||||
} while ([&] {
|
|
||||||
bool r = false;
|
|
||||||
previous_node = current_node;
|
|
||||||
|
|
||||||
if (ts_tree_cursor_goto_first_child(&cursor)
|
|
||||||
|| ts_tree_cursor_goto_next_sibling(&cursor)) {
|
|
||||||
r = true;
|
|
||||||
goto eval;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (ts_tree_cursor_goto_parent(&cursor)) {
|
|
||||||
if (!strcmp(ts_node_type(current_node), "translation_unit")) {
|
|
||||||
r = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ts_tree_cursor_goto_next_sibling(&cursor)) {
|
|
||||||
r = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
eval:
|
|
||||||
if (!strcmp("function_definition", ts_node_type(previous_node))) {
|
|
||||||
puts("^^df");
|
puts("^^df");
|
||||||
|
} break;
|
||||||
goto end;
|
[[likely]] default: { ; } break;
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
if (r) { break; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
free(tbtext);
|
||||||
}());
|
|
||||||
|
if (ts_tree_cursor_goto_first_child(&cursor)
|
||||||
|
|| ts_tree_cursor_goto_next_sibling(&cursor)) {
|
||||||
|
current_node = ts_tree_cursor_current_node(&cursor);
|
||||||
|
tb_case = determine_case(tb_leave_cases, ts_node_type);
|
||||||
|
goto eval;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ts_tree_cursor_goto_parent(&cursor)) {
|
||||||
|
current_node = ts_tree_cursor_current_node(&cursor);
|
||||||
|
if (ts_tree_cursor_goto_next_sibling(&cursor)) {
|
||||||
|
tb_case = determine_case(tb_leave_cases, ts_node_type);
|
||||||
|
goto eval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// deinit
|
// deinit
|
||||||
ts_tree_delete(tree);
|
ts_tree_delete(tree);
|
||||||
@ -102,4 +109,3 @@ int tbtraverse(const char * const code) {
|
|||||||
signed main() {
|
signed main() {
|
||||||
tbtraverse("int main() { return 0; }");
|
tbtraverse("int main() { return 0; }");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
112
source/tbsp.c
Normal file
112
source/tbsp.c
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "tbsp.yy.h"
|
||||||
|
#include "tbsp.tab.h"
|
||||||
|
|
||||||
|
// XXX i am so desperate for #embed, you would not believe
|
||||||
|
#include "TBSP_strings.inc"
|
||||||
|
|
||||||
|
extern int tbsp_yy_init(void);
|
||||||
|
extern int tbsp_yy_deinit(void);
|
||||||
|
|
||||||
|
char * language = NULL;
|
||||||
|
char * verbatim = NULL;
|
||||||
|
char * top = NULL;
|
||||||
|
|
||||||
|
void put_rule_table(const char * const name, rule_type_t type_mask) {
|
||||||
|
char * sprint_buffer;
|
||||||
|
int sprint_r;
|
||||||
|
(void)sprint_r;
|
||||||
|
fputs("const tbcase_t tb_", yyout);
|
||||||
|
fputs(name, yyout);
|
||||||
|
fputs("[] = {\n", yyout);
|
||||||
|
for (int i = 0; i < kv_size(rules); i++) {
|
||||||
|
if (!(kv_A(rules, i).type & type_mask)) { continue; }
|
||||||
|
sprint_r = asprintf(&sprint_buffer,
|
||||||
|
TBSP_case,
|
||||||
|
kv_A(rules, i).string,
|
||||||
|
kv_A(rules, i).target
|
||||||
|
);
|
||||||
|
fputs(sprint_buffer, yyout);
|
||||||
|
free(sprint_buffer);
|
||||||
|
}
|
||||||
|
fputs(" (tbcase_t) { .string = NULL, .case_number = 0 },\n", yyout);
|
||||||
|
fputs("};\n\n", yyout);
|
||||||
|
}
|
||||||
|
|
||||||
|
signed main(const int argc, const char * const * const argv) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
yydebug = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("%s <file>", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tbsp_yy_init();
|
||||||
|
tbsp_tab_init();
|
||||||
|
|
||||||
|
yyin = fopen(argv[1], "r");
|
||||||
|
if (!yyin) {
|
||||||
|
puts("Failed to open file");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//yyout = fopen("tbsp.c", "w");
|
||||||
|
yyout = stdout;
|
||||||
|
|
||||||
|
int yyparse_r = yyparse();
|
||||||
|
if (yyparse_r) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * sprint_buffer;
|
||||||
|
int sprint_r;
|
||||||
|
(void)sprint_r;
|
||||||
|
|
||||||
|
// Header
|
||||||
|
sprint_r = asprintf(&sprint_buffer, TBSP_header, language, language);
|
||||||
|
fputs(sprint_buffer, yyout);
|
||||||
|
free(sprint_buffer);
|
||||||
|
|
||||||
|
// Definition section
|
||||||
|
fputs(top, yyout);
|
||||||
|
|
||||||
|
// Rule section
|
||||||
|
put_rule_table("enter_cases", ENTER_RULE);
|
||||||
|
put_rule_table("leave_cases", LEAVE_RULE);
|
||||||
|
|
||||||
|
fputs(TBSP_traverse_top, yyout);
|
||||||
|
for (int i = 0; i < kv_size(rules); i++) {
|
||||||
|
const char * const case_string = "\
|
||||||
|
case %d: {\n\
|
||||||
|
%s\n\
|
||||||
|
} break;\n\
|
||||||
|
";
|
||||||
|
sprint_r = asprintf(&sprint_buffer,
|
||||||
|
case_string,
|
||||||
|
kv_A(rules, i).target,
|
||||||
|
kv_A(rules, i).code
|
||||||
|
);
|
||||||
|
fputs(sprint_buffer, yyout);
|
||||||
|
free(sprint_buffer);
|
||||||
|
}
|
||||||
|
fputs(TBSP_traverse_bottom, yyout);
|
||||||
|
|
||||||
|
// Code section
|
||||||
|
fputs(verbatim, yyout);
|
||||||
|
|
||||||
|
// Deinit
|
||||||
|
for (int i = 0; i < kv_size(rules); i++) {
|
||||||
|
free(kv_A(rules, i).string);
|
||||||
|
free(kv_A(rules, i).code);
|
||||||
|
}
|
||||||
|
|
||||||
|
tbsp_yy_deinit();
|
||||||
|
free(verbatim);
|
||||||
|
free(language);
|
||||||
|
free(top);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
94
source/tbsp.l
Normal file
94
source/tbsp.l
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
%{
|
||||||
|
#include <sds.h>
|
||||||
|
#include "tbsp.tab.h"
|
||||||
|
|
||||||
|
int code_nesting = 0;
|
||||||
|
|
||||||
|
int code_caller;
|
||||||
|
|
||||||
|
sds buffer;
|
||||||
|
%}
|
||||||
|
|
||||||
|
identifier [a-zA-z][-a-zA-z0-9_]*
|
||||||
|
|
||||||
|
%x IN_DEFINITION_SECTION IN_RULE_SECTION IN_CODE_SECTION
|
||||||
|
%x IN_CODE
|
||||||
|
|
||||||
|
%option nodefault
|
||||||
|
%option noyywrap
|
||||||
|
%%
|
||||||
|
. { yyless(0); BEGIN IN_DEFINITION_SECTION; }
|
||||||
|
|
||||||
|
<IN_DEFINITION_SECTION>{
|
||||||
|
\%top[[:space:]]+\{ {
|
||||||
|
code_caller = IN_DEFINITION_SECTION;
|
||||||
|
BEGIN IN_CODE;
|
||||||
|
return TOP;
|
||||||
|
}
|
||||||
|
\%language[[:space:]] {
|
||||||
|
return LANGUAGE;
|
||||||
|
}
|
||||||
|
{identifier} {
|
||||||
|
yylval.strval = strdup(yytext);
|
||||||
|
return IDENTIFIER;
|
||||||
|
}
|
||||||
|
[[:space:]] { ; }
|
||||||
|
\%\% {
|
||||||
|
BEGIN IN_RULE_SECTION;
|
||||||
|
return SEPARATOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<IN_RULE_SECTION>{
|
||||||
|
\{ {
|
||||||
|
code_caller = IN_RULE_SECTION;
|
||||||
|
BEGIN IN_CODE;
|
||||||
|
}
|
||||||
|
\} { ; }
|
||||||
|
[[:space:]]* { ; }
|
||||||
|
enter[[:space:]] { return ENTER; }
|
||||||
|
leave[[:space:]] { return LEAVE; }
|
||||||
|
{identifier} {
|
||||||
|
yylval.strval = strdup(yytext);
|
||||||
|
return IDENTIFIER;
|
||||||
|
}
|
||||||
|
\%\% {
|
||||||
|
BEGIN IN_CODE_SECTION;
|
||||||
|
return SEPARATOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<IN_CODE>{
|
||||||
|
\{ { ++code_nesting; }
|
||||||
|
\} {
|
||||||
|
if (!code_nesting) {
|
||||||
|
yylval.strval = strdup(buffer);
|
||||||
|
sdsclear(buffer);
|
||||||
|
BEGIN code_caller;
|
||||||
|
return CODE_BLOB;
|
||||||
|
}
|
||||||
|
|
||||||
|
--code_nesting;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
.|\n { buffer = sdscat(buffer, yytext); }
|
||||||
|
}
|
||||||
|
|
||||||
|
<IN_CODE_SECTION>{
|
||||||
|
(.|\n)* {
|
||||||
|
yylval.strval = strdup(yytext);
|
||||||
|
BEGIN IN_DEFINITION_SECTION;
|
||||||
|
return CODE_BLOB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%%
|
||||||
|
|
||||||
|
int tbsp_yy_init(void) {
|
||||||
|
buffer = sdsnew("");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tbsp_yy_deinit(void) {
|
||||||
|
sdsfree(buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
126
source/tbsp.y
Normal file
126
source/tbsp.y
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
%{
|
||||||
|
#include "tbsp.yy.h"
|
||||||
|
|
||||||
|
void yyerror([[maybe_unused]] const char * const s);
|
||||||
|
|
||||||
|
extern char * language;
|
||||||
|
extern char * top;
|
||||||
|
extern char * verbatim;
|
||||||
|
|
||||||
|
int target_counter = 1;
|
||||||
|
|
||||||
|
#define COMA ,
|
||||||
|
%}
|
||||||
|
%code requires {
|
||||||
|
typedef enum {
|
||||||
|
ENTER_RULE = 0b0001,
|
||||||
|
LEAVE_RULE = 0b0010,
|
||||||
|
} rule_type_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rule_type_t type;
|
||||||
|
int target;
|
||||||
|
char * string;
|
||||||
|
char * code;
|
||||||
|
} rule_t;
|
||||||
|
|
||||||
|
#include <kvec.h>
|
||||||
|
typedef kvec_t(rule_t) rule_vector_t;
|
||||||
|
extern rule_vector_t rules;
|
||||||
|
}
|
||||||
|
%code provides {
|
||||||
|
void tbsp_tab_init(void);
|
||||||
|
void tbsp_tab_deinit(void);
|
||||||
|
}
|
||||||
|
%union{
|
||||||
|
char * strval;
|
||||||
|
rule_type_t ruleval;
|
||||||
|
}
|
||||||
|
%token SEPARATOR
|
||||||
|
%token TOP LANGUAGE
|
||||||
|
%token ENTER LEAVE
|
||||||
|
%token<strval> IDENTIFIER CODE_BLOB
|
||||||
|
%type<ruleval> rule_type
|
||||||
|
%type<strval> rule_selector
|
||||||
|
%%
|
||||||
|
document
|
||||||
|
: %empty
|
||||||
|
| definition_section SEPARATOR rule_section SEPARATOR code_section
|
||||||
|
;
|
||||||
|
|
||||||
|
definition_section
|
||||||
|
: %empty
|
||||||
|
| top definition_section
|
||||||
|
| language definition_section
|
||||||
|
;
|
||||||
|
|
||||||
|
top
|
||||||
|
: TOP CODE_BLOB {
|
||||||
|
if (top) {
|
||||||
|
puts("error: reee");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
top = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
language
|
||||||
|
: LANGUAGE IDENTIFIER {
|
||||||
|
language = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rule_section
|
||||||
|
: %empty
|
||||||
|
| rule rule_section
|
||||||
|
;
|
||||||
|
|
||||||
|
rule
|
||||||
|
: rule_type rule_selector CODE_BLOB {
|
||||||
|
kv_push(rule_t, rules, (rule_t) {
|
||||||
|
.type = $1 COMA
|
||||||
|
.target = target_counter COMA
|
||||||
|
.string = $2 COMA
|
||||||
|
.code = $3 COMA
|
||||||
|
});
|
||||||
|
++target_counter;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
rule_type
|
||||||
|
: %empty { $$ = 0; }
|
||||||
|
| ENTER rule_type { $$ |= ENTER_RULE; }
|
||||||
|
| LEAVE rule_type { $$ |= LEAVE_RULE; }
|
||||||
|
;
|
||||||
|
|
||||||
|
rule_selector
|
||||||
|
: IDENTIFIER { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
code_section
|
||||||
|
: CODE_BLOB {
|
||||||
|
verbatim = $1;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
rule_vector_t rules;
|
||||||
|
|
||||||
|
void yyerror(const char * const s) {
|
||||||
|
puts("yyerror");
|
||||||
|
}
|
||||||
|
|
||||||
|
void tbsp_tab_init(void) {
|
||||||
|
kv_init(rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tbsp_tab_deinit(void) {
|
||||||
|
for (int i = 0; i < kv_size(rules); i++) {
|
||||||
|
free(kv_A(rules, i).string);
|
||||||
|
free(kv_A(rules, i).code);
|
||||||
|
}
|
||||||
|
|
||||||
|
kv_destroy(rules);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user