Initial Lexer/Parser default tip

Mon, 01 Sep 2025 00:14:59 +0800

author
Gong Zhile <gongzl@stu.hebust.edu.cn>
date
Mon, 01 Sep 2025 00:14:59 +0800
changeset 0
59c92fa19678

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;
+    }
+;
+
+%%

mercurial