[vlc-commits] JSON grammar

Rémi Denis-Courmont git at videolan.org
Sun Sep 27 15:16:38 CEST 2020


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Sep 27 15:30:49 2020 +0300| [4a887815dec398254c0e43985b7292319097e234] | committer: Rémi Denis-Courmont

JSON grammar

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=4a887815dec398254c0e43985b7292319097e234
---

 modules/demux/Makefile.am    |   2 +
 modules/demux/json/grammar.y | 228 +++++++++++++++++++++++++++++++++++++++++++
 modules/demux/json/lexicon.l |  12 +--
 3 files changed, 236 insertions(+), 6 deletions(-)

diff --git a/modules/demux/Makefile.am b/modules/demux/Makefile.am
index cde3c90776..d7b8df6ece 100644
--- a/modules/demux/Makefile.am
+++ b/modules/demux/Makefile.am
@@ -513,8 +513,10 @@ libdemux_mock_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(demuxdir)'
 libdemux_mock_plugin_la_LIBADD = $(LIBM)
 noinst_LTLIBRARIES += libdemux_mock_plugin.la
 
+BUILT_SOURCES += demux/json/grammar.h
 libvlc_json_la_SOURCES = \
 	demux/json/lexicon.l \
+	demux/json/grammar.y \
 	demux/json/json.c demux/json/json.h
 libvlc_json_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/demux/json
 libvlc_json_la_LIBADD = $(LTLIBVLCCORE) ../compat/libcompat.la
diff --git a/modules/demux/json/grammar.y b/modules/demux/json/grammar.y
new file mode 100644
index 0000000000..8d83f9a40b
--- /dev/null
+++ b/modules/demux/json/grammar.y
@@ -0,0 +1,228 @@
+/*****************************************************************************
+ * json/grammar.y: JSON parser
+ *****************************************************************************
+ * Copyright © 2020 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+%define api.pure full
+%lex-param { void *scanner }
+%parse-param { void *log }
+%parse-param { void *scanner }
+%parse-param { struct json_object *result }
+
+%{
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "json.h"
+
+static void json_array_free(struct json_array *);
+
+static void json_value_free(struct json_value *v)
+{
+	switch (v->type) {
+		case JSON_NULL:
+		case JSON_BOOLEAN:
+		case JSON_NUMBER:
+			break;
+
+		case JSON_STRING:
+			free(v->string);
+			break;
+
+		case JSON_ARRAY:
+			json_array_free(&v->array);
+			break;
+
+		case JSON_OBJECT:
+			json_free(&v->object);
+			break;
+	}
+}
+
+static void json_array_free(struct json_array *a)
+{
+	for (size_t i = 0; i < a->size; i++)
+		json_value_free(&a->entries[i]);
+
+	free(a->entries);
+}
+
+static void json_member_free(struct json_member *m)
+{
+	free(m->name);
+	json_value_free(&m->value);
+}
+
+void json_free(struct json_object *o)
+{
+	for (size_t i = 0; i < o->count; i++)
+		json_member_free(&o->members[i]);
+
+	free(o->members);
+}
+
+static void json_array_init(struct json_array *a)
+{
+	a->size = 0;
+	a->entries = NULL;
+}
+
+static void json_array_append(struct json_array *a, struct json_value v)
+{
+	size_t size = a->size;
+	struct json_value *ne = realloc(a->entries, (size + 1) * sizeof (v));
+
+	if (ne != NULL) {
+		ne[size] = v;
+		a->entries = ne;
+		a->size = size + 1;
+	} else
+		json_value_free(&v);
+
+}
+
+static void json_init(struct json_object *o)
+{
+	o->count = 0;
+	o->members = NULL;
+}
+
+static void json_append(struct json_object *o, struct json_member m)
+{
+	size_t count = o->count;
+	struct json_member *nm = realloc(o->members, (count + 1) * sizeof (m));
+
+	if (nm != NULL) {
+		nm[count] = m;
+		o->members = nm;
+		o->count = count + 1;
+	} else
+		json_member_free(&m);
+}
+
+%}
+
+%union {
+	bool boolean;
+	double number;
+	char *string;
+	struct json_value value;
+	struct json_array array;
+	struct json_member member;
+	struct json_object object;
+}
+
+%token VALUE_NULL
+%token <boolean> BOOLEAN
+%token <number> NUMBER
+%token <string> STRING
+
+%type <value> value
+%type <array> values
+%type <array> array
+%type <member> member
+%type <object> members
+%type <object> object
+
+%{
+
+static void yyerror(void *log, void *scanner, struct json_object *result,
+			const char *msg)
+{
+	json_parse_error(log, msg);
+	(void) scanner; (void) result;
+}
+
+extern int yylex_init(void *);
+extern void yyset_in(FILE *, void *);
+extern int yylex(YYSTYPE *value, void *scanner);
+extern int yylex_destroy(void *);
+
+%}
+
+%destructor { fprintf(stderr, "freeing string %s\n", $$); free($$); } <string>
+%destructor { fprintf(stderr, "freeing value %p\n", &$$); json_value_free(&$$); } <value>
+%destructor { fprintf(stderr, "freeing array %p\n", &$$); json_array_free(&$$); } <array>
+%destructor { fprintf(stderr, "freeing member %p\n", &$$); json_member_free(&$$); } <member>
+%destructor { fprintf(stderr, "freeing object %p\n", &$$); json_free(&$$); } <object>
+
+%%
+
+parse:
+	object YYEOF	{ *result = $1; }
+;
+
+object:
+	'{' '}'			{ json_init(&$$); }
+|	'{' members '}'		{ $$ = $2; }
+;
+
+array:
+	'[' ']'			{ json_array_init(&$$); }
+|	'[' values ']'		{ $$ = $2; }
+;
+
+members:
+	member			{ json_init(&$$); json_append(&$$, $1); }
+|	members ',' member	{ $$ = $1; json_append(&$$, $3); }
+;
+
+member:
+	STRING ':' value	{ $$.name = $1; $$.value = $3; }
+;
+
+values:
+	value			{ json_array_init(&$$);
+					json_array_append(&$$, $1); }
+|	values ',' value	{ $$ = $1;
+					json_array_append(&$$, $3); }
+;
+
+value:
+	VALUE_NULL		{ $$.type = JSON_NULL; }
+|	BOOLEAN			{ $$.type = JSON_BOOLEAN;
+					$$.boolean = $1; }
+|	NUMBER			{ $$.type = JSON_NUMBER;
+					$$.number = $1; }
+|	STRING			{ $$.type = JSON_STRING;
+					$$.string = $1; }
+|	array			{ $$.type = JSON_ARRAY;
+					$$.array = $1; }
+|	object			{ $$.type = JSON_OBJECT;
+					$$.object = $1; }
+;
+
+%%
+
+int json_parse(void *log, FILE *in, struct json_object *result)
+{
+	void *scanner;
+	int ret = yylex_init(&scanner);
+
+	if (ret)
+		return ret;
+
+	yyset_in(in, scanner);
+	ret = yyparse(log, scanner, result);
+	yylex_destroy(scanner);
+	return ret;
+}
diff --git a/modules/demux/json/lexicon.l b/modules/demux/json/lexicon.l
index 9aa655a245..8b8a8b8ab5 100644
--- a/modules/demux/json/lexicon.l
+++ b/modules/demux/json/lexicon.l
@@ -19,6 +19,7 @@
  *****************************************************************************/
 
 %option 8bit
+%option bison-bridge
 %option nodefault
 %option noinput
 %option reentrant
@@ -35,8 +36,7 @@
 #include <stdbool.h>
 #include <stdlib.h>
 #include "json.h"
-
-enum { VALUE_NULL, BOOLEAN, NUMBER, STRING };
+#include "grammar.h"
 
 %}
 
@@ -46,18 +46,18 @@ enum { VALUE_NULL, BOOLEAN, NUMBER, STRING };
 
 "null" {		return VALUE_NULL; }
 
-"false"	{		//yylval->boolean = false;
+"false"	{		yylval->boolean = false;
 			return BOOLEAN; }
 
-"true" {		//yylval->boolean = true;
+"true" {		yylval->boolean = true;
 			return BOOLEAN; }
 
 -?(0|([1-9][0-9]*))(\.[0-9]+)?(e[+-]?[0-9]+)? {
-			//yylval->number = atof(yytext);
+			yylval->number = atof(yytext);
 			return NUMBER; }
 
 \"([^"\\]|\\[\"\\/bfnrt]|\\u[0-9A-Fa-f]{4})*\" {
-			//yylval->string = json_unescape(yytext + 1, yyleng - 2);
+			yylval->string = json_unescape(yytext + 1, yyleng - 2);
 			return STRING; }
 
 [{}:,[\]] {		return *yytext; }



More information about the vlc-commits mailing list