From 28b3b1678c38be419a750ac1816a1ae9fa9763ba Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 19 May 2016 01:15:33 -0500 Subject: [PATCH] ioc/dbStatic: Add JSON parsing of field values The parsing removes all white-space outside of quotes from the JSON. dbRecordField() now strips quotes from simple string values itself. --- src/ioc/dbStatic/dbLex.l | 44 ++++++++++++++++--- src/ioc/dbStatic/dbLexRoutines.c | 5 +++ src/ioc/dbStatic/dbYacc.y | 75 +++++++++++++++++++++++++++++--- 3 files changed, 111 insertions(+), 13 deletions(-) diff --git a/src/ioc/dbStatic/dbLex.l b/src/ioc/dbStatic/dbLex.l index 37de82647..e79120a0e 100644 --- a/src/ioc/dbStatic/dbLex.l +++ b/src/ioc/dbStatic/dbLex.l @@ -1,11 +1,12 @@ /*************************************************************************\ -* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne +* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ + newline "\n" backslash "\\" doublequote "\"" @@ -15,6 +16,18 @@ escape {backslash}. stringchar [^"\n\\] bareword [a-zA-Z0-9_\-+:.\[\]<>;] +punctuation [:,\[\]{}] +normalchar [^"\\\0-\x1f] +escapedchar ({backslash}["\\/bfnrt]) +hexdigit [0-9a-fA-F] +unicodechar ({backslash}"u"{hexdigit}{4}) +jsonchar ({normalchar}|{escapedchar}|{unicodechar}) +jsondqstr ({doublequote}{jsonchar}*{doublequote}) +int ("-"?([0-9]|[1-9][0-9]+)) +frac ("."[0-9]+) +exp ([eE][+-]?[0-9]+) +number ({int}{frac}?{exp}?) + %{ #undef YY_INPUT #define YY_INPUT(b,r,ms) (r=(*db_yyinput)((char *)b,ms)) @@ -27,6 +40,8 @@ static int yyreset(void) %} +%x JSON + %% "include" return(tokenINCLUDE); @@ -49,18 +64,18 @@ static int yyreset(void) "variable" return(tokenVARIABLE); {bareword}+ { /* unquoted string or number */ - yylval.Str = dbmfStrdup(yytext); + yylval.Str = dbmfStrdup((char *) yytext); return(tokenSTRING); } {doublequote}({stringchar}|{escape})*{doublequote} { /* quoted string */ - yylval.Str = dbmfStrdup(yytext+1); + yylval.Str = dbmfStrdup((char *) yytext+1); yylval.Str[strlen(yylval.Str)-1] = '\0'; return(tokenSTRING); } %.* { /*C definition in recordtype*/ - yylval.Str = dbmfStrdup(yytext+1); + yylval.Str = dbmfStrdup((char *) yytext+1); return(tokenCDEFS); } @@ -71,13 +86,30 @@ static int yyreset(void) "," return(yytext[0]); {comment}.* ; -{whitespace} ; {doublequote}({stringchar}|{escape})*{newline} { /* bad string */ yyerrorAbort("Newline in string, closing quote missing"); } -. { +"null" return jsonNULL; +"true" return jsonTRUE; +"false" return jsonFALSE; + +{punctuation} return yytext[0]; + +{jsondqstr} { + yylval.Str = dbmfStrdup((char *) yytext); + return jsonSTRING; +} + +{number} { + yylval.Str = dbmfStrdup((char *) yytext); + return jsonNUMBER; +} + +{whitespace} ; + +. { char message[40]; YY_BUFFER_STATE *dummy=0; diff --git a/src/ioc/dbStatic/dbLexRoutines.c b/src/ioc/dbStatic/dbLexRoutines.c index 6046c91a6..ff9f04db1 100644 --- a/src/ioc/dbStatic/dbLexRoutines.c +++ b/src/ioc/dbStatic/dbLexRoutines.c @@ -1048,6 +1048,11 @@ static void dbRecordField(char *name,char *value) yyerror(NULL); return; } + if (*value == '"') { + /* jsonSTRING values still have their quotes */ + value++; + value[strlen(value) - 1] = 0; + } dbTranslateEscape(value, value); /* yuck: in-place, but safe */ status = dbPutString(pdbentry,value); if(status) { diff --git a/src/ioc/dbStatic/dbYacc.y b/src/ioc/dbStatic/dbYacc.y index c5f64eef3..abcc11981 100644 --- a/src/ioc/dbStatic/dbYacc.y +++ b/src/ioc/dbStatic/dbYacc.y @@ -17,6 +17,11 @@ static int yyAbort = 0; %start database +%union +{ + char *Str; +} + %token tokenINCLUDE tokenPATH tokenADDPATH %token tokenALIAS tokenMENU tokenCHOICE tokenRECORDTYPE %token tokenFIELD tokenINFO tokenREGISTRAR @@ -24,10 +29,10 @@ static int yyAbort = 0; %token tokenRECORD tokenGRECORD tokenVARIABLE tokenFUNCTION %token tokenSTRING tokenCDEFS -%union -{ - char *Str; -} +%token jsonNULL jsonTRUE jsonFALSE +%token jsonNUMBER jsonSTRING +%type json_value json_object json_array +%type json_members json_pair json_elements %% @@ -247,10 +252,11 @@ record_body: /* empty */ record_field_list: record_field_list record_field | record_field; -record_field: tokenFIELD '(' tokenSTRING ',' tokenSTRING ')' +record_field: tokenFIELD '(' tokenSTRING ',' + { BEGIN JSON; } json_value { BEGIN INITIAL; } ')' { - if(dbStaticDebug>2) printf("record_field %s %s\n",$3,$5); - dbRecordField($3,$5); dbmfFree($3); dbmfFree($5); + if(dbStaticDebug>2) printf("record_field %s %s\n",$3,$6); + dbRecordField($3,$6); dbmfFree($3); dbmfFree($6); } | tokenINFO '(' tokenSTRING ',' tokenSTRING ')' { @@ -270,6 +276,61 @@ alias: tokenALIAS '(' tokenSTRING ',' tokenSTRING ')' dbAlias($3,$5); dbmfFree($3); dbmfFree($5); }; +json_object: '{' '}' +{ + $$ = "{}"; + if (dbStaticDebug>2) printf("json %s\n", $$); +} + | '{' json_members '}' +{ + $$ = dbmfStrcat3("{", $2, "}"); + dbmfFree($2); + if (dbStaticDebug>2) printf("json %s\n", $$); +}; + +json_members: json_pair + | json_pair ',' json_members +{ + $$ = dbmfStrcat3($1, ",", $3); + dbmfFree($1); dbmfFree($3); + if (dbStaticDebug>2) printf("json %s\n", $$); +}; + +json_pair: jsonSTRING ':' json_value +{ + $$ = dbmfStrcat3($1, ":", $3); + dbmfFree($1); dbmfFree($3); + if (dbStaticDebug>2) printf("json %s\n", $$); +}; + +json_array: '[' ']' +{ + $$ = "[]"; + if (dbStaticDebug>2) printf("json %s\n", $$); +} + | '[' json_elements ']' +{ + $$ = dbmfStrcat3("[", $2, "]"); + dbmfFree($2); + if (dbStaticDebug>2) printf("json %s\n", $$); +}; + +json_elements: json_value + | json_value ',' json_elements +{ + $$ = dbmfStrcat3($1, ",", $3); + dbmfFree($1); dbmfFree($3); + if (dbStaticDebug>2) printf("json %s\n", $$); +}; + +json_value: jsonNULL { $$ = "null"; } + | jsonTRUE { $$ = "true"; } + | jsonFALSE { $$ = "false"; } + | jsonNUMBER + | jsonSTRING + | json_array + | json_object ; + %%