Mon, 01 Sep 2025 00:14:59 +0800
Initial Lexer/Parser
| .hgignore | file | annotate | diff | comparison | revisions | |
| meson.build | file | annotate | diff | comparison | revisions | |
| tlvast.h | file | annotate | diff | comparison | revisions | |
| tlvc.c | file | annotate | diff | comparison | revisions | |
| tlvc.l | file | annotate | diff | comparison | revisions | |
| tlvc.y | file | annotate | diff | comparison | revisions |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Mon Sep 01 00:14:59 2025 +0800 @@ -0,0 +1,42 @@ +syntax: glob + +# Meson build directories +build*/ +meson-private/ +meson-logs/ +compile_commands.json +install_manifest.txt + +# Object and binary files +*.o +*.a +*.so +*.so.* +*.dylib +*.dll +*.exe + +# Debug symbols +*.pdb +*.dSYM/ +*.stackdump + +# Generated source files +*.generated.c +*.generated.h + +# Backup / temporary files +*~ +*.swp +*.tmp +*.bak + +# Editor-specific +.vscode/ +.idea/ + +# OS junk +.DS_Store +Thumbs.db + +.cache/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/meson.build Mon Sep 01 00:14:59 2025 +0800 @@ -0,0 +1,41 @@ +project('tlvc', 'c', + version : '0.1', + default_options : ['warning_level=3']) + +flex = find_program('flex') +bison = find_program('bison') + +lexer = generator( + flex, + output : [ '@BASENAME@.yy.c', '@BASENAME@.yy.h' ], + arguments : [ + '--outfile=@OUTPUT0@', + '--header-file=@OUTPUT1@', + '@INPUT@' + ] +) + +parser = generator( + bison, + output : [ '@BASENAME@.tab.c', '@BASENAME@.tab.h' ], + arguments : [ + '-d', '@INPUT@', '-v', + '--output=@OUTPUT0@', + '--defines=@OUTPUT1@' + ] +) + +parser_src = parser.process('tlvc.y') +lexer_src = lexer.process('tlvc.l') + +SOURCES = [ + 'tlvc.c', + parser_src, + lexer_src, +] + +exe = executable('tlvc', SOURCES, + include_directories : include_directories('.'), + install : true) + +test('basic', exe)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tlvast.h Mon Sep 01 00:14:59 2025 +0800 @@ -0,0 +1,36 @@ +#ifndef _TLVAST_H_ +#define _TLVAST_H_ + +#include <stddef.h> +#include <sys/queue.h> + +enum tlv_ftype { + TLV_TYPE_NONE, + TLV_TYPE_STRING, + TLV_TYPE_U8, + TLV_TYPE_U16, + TLV_TYPE_U32, + TLV_TYPE_U64, +}; + +struct tlv_field { + enum tlv_ftype type; + char *name; + int tag; + TAILQ_ENTRY(tlv_field) entries; +}; + +TAILQ_HEAD(tlv_field_list_head, tlv_field); + +struct tlv { + char *name; + int tag; + TAILQ_HEAD(fields_head, tlv_field) fields; + TAILQ_ENTRY(tlv) entries; +}; + +TAILQ_HEAD(tlv_list_head, tlv); + +extern struct tlv_list_head g_tlvs; + +#endif /* _TLBAST_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tlvc.c Mon Sep 01 00:14:59 2025 +0800 @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/queue.h> + +#include "tlvast.h" +#include "tlvc.tab.h" + +struct tlv_list_head g_tlvs; + +void yyerror(YYLTYPE *yylloc, const char *s) +{ + fprintf(stderr, "Synatx error (%d:%d): %s\n", + yylloc->first_line, yylloc->first_column, s); +} + +int main(int argc, char **argv) +{ + TAILQ_INIT(&g_tlvs); + yyparse(); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tlvc.l Mon Sep 01 00:14:59 2025 +0800 @@ -0,0 +1,30 @@ +%{ +#include <string.h> +#include <stdlib.h> +#include "tlvast.h" +#include "tlvc.tab.h" +%} + +%option noyywrap +%option yylineno + +%% +"message" { return MESSAGE; } + +"u8" { yylval.num = TLV_TYPE_U8; return TYPE; } +"u16" { yylval.num = TLV_TYPE_U16; return TYPE; } +"u32" { yylval.num = TLV_TYPE_U32; return TYPE; } +"u64" { yylval.num = TLV_TYPE_U64; return TYPE; } + +"STRING" { yylval.num = TLV_TYPE_STRING; return TYPE; } + +0x[0-9a-fA-F]+ { yylval.num = (int)strtol(yytext,NULL,16); return NUMBER; } + +[a-zA-Z_][a-zA-Z0-9_]* { yylval.str = strdup(yytext); return IDENT; } + +[ \t\r\n]+ ; // skip whitespace +"{" { return '{'; } +"}" { return '}'; } +";" { return ';'; } +. { fprintf(stderr,"Unexpected char: %c\n", yytext[0]); } +%%
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tlvc.y Mon Sep 01 00:14:59 2025 +0800 @@ -0,0 +1,81 @@ +%locations +%define parse.error verbose + +%{ +#include "tlvast.h" +#include "tlvc.yy.h" +extern void yyerror(const char *s); +int field_index = 0; +%} + +%union { + int num; + char *str; + struct tlv_field *field; + struct tlv_field_list_head *field_list; + struct tlv *msg; +} + +%token <str> IDENT +%token <num> TYPE +%token <num> NUMBER +%token MESSAGE + +%type <msg> message +%type <field> field +%type <field_list> field_list + +%% + +input: + /* empty */ + | input message { + TAILQ_INSERT_TAIL(&g_tlvs, $2, entries); + } +; + +message: + MESSAGE IDENT NUMBER '{' field_list '}' { + struct tlv *m = malloc(sizeof(*m)); + m->name = strdup($2); + m->tag = $3; + TAILQ_INIT(&m->fields); + + struct tlv_field *f; + TAILQ_FOREACH(f, $5, entries) { + TAILQ_INSERT_TAIL(&m->fields, f, entries); + } + + $$ = m; + } +; + +field_list: + /* empty */ { + $$ = NULL; + } + | field_list field { + if ($1 == NULL) { + struct tlv_field_list_head *list = malloc(sizeof(*list)); + TAILQ_INIT(list); + TAILQ_INSERT_TAIL(list, $2, entries); + $$ = list; + } else { + TAILQ_INSERT_TAIL($1, $2, entries); + $$ = $1; + } + field_index = 0; + } +; + +field: + TYPE IDENT ';' { + struct tlv_field *f = malloc(sizeof(*f)); + f->type = $1; + f->name = strdup($2); + f->tag = field_index++; + $$ = f; + } +; + +%%