1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
/**
*
* To generate C++/Header files run:
* bison.exe -d -l -pjson_ -o clJSONObjectParser.cpp clJSONObjectParser.y
*/
%{
#define YYTOKENTYPE
#define YYSTYPE_IS_DECLARED
#define YYSTYPE char*
#include <wx/string.h>
#include "JSLexerTokens.h"
#include "JSLexerAPI.h" // Contains yygut definition
#include "JSLookUpTable.h"
void yyerror (void* yyscanner, char const *msg);
/* our parser will invoke this function json_lex
* which is a wrapper to the real lex function: js_lex
*/
extern int json_lex(void* yyscanner);
/* the real lex function */
extern int js_lex(void* yyscanner);
/* consume tokens until found 'until' */
static void clParseJS_ReadUntil(void *scanner, int until);
struct clJSONParserData {
JSLookUpTable::Ptr_t lookup;
JSObject::Vec_t objStack;
};
static void clParseJS_FinalizeObject(clJSONParserData* parserData, const wxString& objType);
#define PARSER_DATA() static_cast<clJSONParserData*>(static_cast<JSLexerUserData*>(jsLexerGetUserData(scanner))->parserData)
%}
%lex-param {void* scanner}
%parse-param {void* scanner}
%token kJS_FUNCTION kJS_VAR kJS_DOT kJS_THIS
%token kJS_CATCH kJS_THROW kJS_SWITCH kJS_CASE
%token kJS_FOR kJS_STRING kJS_IDENTIFIER kJS_PROTOTYPE
%token kJS_RETURN kJS_NEW kJS_TRUE kJS_FALSE kJS_NULL
%token kJS_DEC_NUMBER kJS_OCTAL_NUMBER kJS_HEX_NUMBER
%token kJS_FLOAT_NUMBER kJS_PLUS_PLUS kJS_MINUS_MINUS
%token kJS_LS kJS_RS kJS_LE kJS_GE kJS_EQUAL
%token kJS_NOT_EQUAL kJS_AND_AND kJS_OR_OR kJS_STAR_EQUAL kJS_SLASH_EQUAL
%token kJS_DIV_EQUAL kJS_PLUS_EQUAL kJS_MINUS_EQUAL kJS_RS_ASSIGN kJS_AND_EQUAL
%token kJS_POW_EQUAL kJS_OR_EQUAL kJS_VOID kJS_TYPEOF kJS_DELETE kJS_INSTANCEOF
%token kJS_EQUAL3 kJS_LS_ASSIGN
%start program
%%
program:
| literalObject {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, parserData->lookup->GenerateNewType());
}
| literalArray {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "Array");
}
| number {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "Number");
}
| kJS_STRING {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "String");
}
| kJS_TRUE {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "Boolean");
}
| kJS_FALSE {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "Boolean");
}
;
literalObject: '{' keyValues '}'
;
literalArray: '[' { clParseJS_ReadUntil(scanner, ']'); } ']'
;
propertyKey: kJS_IDENTIFIER {
clJSONParserData *parserData = PARSER_DATA();
JSObject::Ptr_t o = parserData->lookup->NewObject();
o->SetName(::jsLexerCurrentToken(scanner));
parserData->objStack.push_back(o);
}
| kJS_STRING {
clJSONParserData *parserData = PARSER_DATA();
JSObject::Ptr_t o = parserData->lookup->NewObject();
wxString name = ::jsLexerCurrentToken(scanner);
name.Remove(0, 1).RemoveLast();
o->SetName(name);
parserData->objStack.push_back(o);
}
;
keyValues: keyValue
| keyValues ',' keyValue
;
/** JSON object key: value **/
keyValue: /* empty */
| propertyKey ':' number {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "Number");
}
| propertyKey ':' literalObject {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, parserData->lookup->GenerateNewType());
}
| propertyKey ':' literalArray {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "Array");
}
| propertyKey ':' kJS_STRING {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "String");
}
| propertyKey ':' kJS_NULL {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "null");
}
| propertyKey ':' kJS_TRUE {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "Boolean");
}
| propertyKey ':' kJS_FALSE {
clJSONParserData *parserData = PARSER_DATA();
clParseJS_FinalizeObject(parserData, "Boolean");
}
;
number: kJS_DEC_NUMBER
| kJS_HEX_NUMBER
| kJS_OCTAL_NUMBER
| kJS_FLOAT_NUMBER
;
%%
void yyerror (void* yyscanner, char const *msg) {}
/**
* @brief a wrapper for the common used lexer
*/
int json_lex(void* yyscanner) { return js_lex(yyscanner); }
static void clParseJS_FinalizeObject(clJSONParserData* parserData, const wxString& objType)
{
// take the current object
JSObject::Ptr_t o = parserData->objStack.at(parserData->objStack.size() - 1);
o->SetType(objType);
o->SetPath(objType);
if(parserData->objStack.size() > 1) {
// we are done with this object, remove it from the stack
parserData->objStack.pop_back();
JSObject::Ptr_t parent = parserData->objStack.at(parserData->objStack.size() - 1);
parent->AddProperty(o);
}
}
//--------------------------
// Public API
//--------------------------
JSObject::Ptr_t clParseJSVariable(const wxString& content, JSLookUpTable::Ptr_t lookup)
{
void* scanner = ::jsLexerNew(content);
// set the parser data
JSLexerUserData *lexerData = ::jsLexerGetUserData(scanner);
clJSONParserData *parserData = new clJSONParserData;
parserData->lookup = lookup;
lexerData->parserData = parserData;
// we start the parsing with an object in the stack
JSObject::Ptr_t result = lookup->NewObject();
result->SetUndefined();
parserData->objStack.push_back(result);
// parse
json_parse(scanner);
wxDELETE(parserData);
// destroy the scanner
::jsLexerDestroy(&scanner);
return result;
}
static void clParseJS_ReadUntil(void *scanner, int until)
{
JSLexerToken token;
int depth(0);
while(true) {
// EOF?
int type = json_lex(scanner);
if(type == 0) break;
if(type == '{') {
++depth;
} else if(type == '}') {
--depth;
}
// breaking condition
if((type == until) && (depth == 0)) {
::jsLexerUnget(scanner);
break;
}
}
}
|