Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
|
Go to the documentation of this file.
71 #define CHARS_LINE_LEN 8
73 static const void* s_vpJsonValid = (
void*)
"JSON";
74 static const void* s_vpIteratorValid = (
void*)
"iterator";
76 static uint32_t s_uiaTrue[] = { 116, 114, 117, 101 };
77 static uint32_t s_uiaFalse[] = { 102, 97, 108, 115, 101 };
78 static uint32_t s_uiaNull[] = { 110, 117, 108, 108 };
79 static aint s_uiTrueLen = 4;
80 static aint s_uiFalseLen = 5;
81 static aint s_uiNullLen = 4;
82 static char* s_cpTrue =
"true";
83 static char* s_cpFalse =
"false";
84 static char* s_cpNull =
"null";
85 static uint32_t s_uiOpenCurly = 123;
86 static uint32_t s_uiCloseCurly = 125;
87 static uint32_t s_uiOpenSquare = 91;
88 static uint32_t s_uiCloseSquare = 93;
89 static uint32_t s_uiColon = 58;
90 static uint32_t s_uiComma = 44;
91 static uint32_t s_uiSpace = 32;
92 static uint32_t s_uiLineEnd = 10;
93 static uint32_t s_uiQuote = 34;
94 static uint32_t s_uiReverseSolidus = 0x5C;
95 static uint32_t s_uiLowerU = 0x75;
97 static void vParseInput(
json* spJson);
99 static void vIndent(
aint uiIndent);
100 static void vFindKeyValues(
json* spJson,
json_iterator* spIt,
const uint32_t *uipKey, uint32_t uiLength, json_value* spValue);
101 static void vBreakIndent(
json* spJson,
aint uiIndent);
102 static void vPushObject(
json* spJson, json_value* spValue,
abool bArray);
105 static void vPushValue(
json* spJson, json_value* spValue);
106 static void vWalkCount(
json* spJson, json_value* spValue);
122 memset((
void*) spJson, 0,
sizeof(
json));
125 spJson->vpVecInput =
vpVecCtor(vpMem,
sizeof(uint8_t), 4096);
126 spJson->vpVecOutput =
vpVecCtor(vpMem,
sizeof(uint32_t), 8192);
129 spJson->vpVecTreeList =
vpVecCtor(vpMem,
sizeof(json_value*), 512);
130 spJson->vpVecChildList =
vpVecCtor(vpMem,
sizeof(json_value*), 512);
131 spJson->vpVecKeyList =
vpVecCtor(vpMem,
sizeof(json_value*), 512);
132 spJson->vpVecScratch32 =
vpVecCtor(vpMem,
sizeof(uint32_t), 4096);
134 spJson->vpVecIterators =
vpVecCtor(vpMem,
sizeof(
void*), 32);
135 spJson->vpVecBuilders =
vpVecCtor(vpMem,
sizeof(
void*), 32);
138 spJson->vpVecChars =
vpVecCtor(vpMem,
sizeof(uint32_t), 4096);
139 spJson->vpVecAscii =
vpVecCtor(vpMem,
sizeof(uint8_t), 4096);
143 spJson->vpVecChildIndexes =
vpVecCtor(vpMem,
sizeof(
aint), 1024);
145 spJson->vpVecValues =
vpVecCtor(vpMem,
sizeof(json_value), 128);
147 spJson->vpVecChildPointers =
vpVecCtor(vpMem,
sizeof(json_value*), 128);
151 spJson->vpMem = vpMem;
152 spJson->spException = spEx;
154 return (
void*) spJson;
169 void* vpMem = spJson->
vpMem;
171 fclose(spJson->
spIn);
176 memset((
void*) spJson, 0,
sizeof(
json));
189 if(vpCtx && (((
json*)vpCtx)->vpValidate == s_vpJsonValid)){
209 if((vpCtx == NULL) || (spJson->
vpValidate != s_vpJsonValid)){
212 char caBuf[PATH_MAX + 128];
213 size_t uiSize = PATH_MAX + 128;
220 fclose(spJson->
spIn);
223 if(!cpFileName || !cpFileName[0]){
227 spJson->
spIn = fopen(cpFileName,
"rb");
229 snprintf(caBuf, uiSize,
"can't open input file: %s", cpFileName);
233 iaBom[0] = fgetc(spJson->
spIn);
234 iaBom[1] = fgetc(spJson->
spIn);
235 iaBom[2] = fgetc(spJson->
spIn);
236 ucaBom[0] = (uint8_t) iaBom[0];
237 ucaBom[1] = (uint8_t) iaBom[1];
238 ucaBom[2] = (uint8_t) iaBom[2];
239 if (iaBom[0] == EOF) {
240 snprintf(caBuf, uiSize,
"input file is empty: %s", cpFileName);
243 if (iaBom[1] == EOF) {
246 }
else if (iaBom[2] == EOF) {
250 if (!(ucaBom[0] == 0xEF && ucaBom[1] == 0xBB && ucaBom[2] == 0xBF)) {
254 uint8_t ucGotBuf[1024];
255 size_t uiGot = fread(ucGotBuf, 1, 1024, spJson->
spIn);
258 uiGot = fread(ucGotBuf, 1, 1024, spJson->
spIn);
261 fclose(spJson->
spIn);
269 sppValues[ui] = &spJson->
spValues[ui];
291 if((vpCtx == NULL) || (spJson->
vpValidate != s_vpJsonValid)){
298 if (uiDataLen >= 3) {
299 if (ucpData[0] == 0xEF && ucpData[1] == 0xBB && ucpData[2] == 0xBF) {
312 sppValues[ui] = &spJson->
spValues[ui];
331 if((vpCtx == NULL) || (spJson->
vpValidate != s_vpJsonValid)){
334 uint8_t* ucpReturn = NULL;
342 vPushValue(spJson, spValue);
367 if((vpCtx == NULL) || (spJson->
vpValidate != s_vpJsonValid)){
372 aint uiOffset, uiChars;
374 const char* cpNextLine;
377 if (!ucpChars || !spLine || !uiLines) {
381 for (ui = 0; ui < uiLines; ui++, spLine++) {
387 printf(
"%s", cpNextLine);
397 printf(
"%s", cpNextLine);
414 if((vpCtx == NULL) || (spJson->
vpValidate != s_vpJsonValid)){
419 vReintrantValueDisplay(spJson, spValue);
435 void* vpReturn = NULL;
437 if((vpCtx == NULL) || (spJson->
vpValidate != s_vpJsonValid)){
440 uint32_t uiLength = (uint32_t) strlen(cpKey);
445 const uint8_t* ucpUnsignedKey = (uint8_t*)cpKey;
446 for (; ui < uiLength; ui++) {
447 uipKey[ui] = (uint32_t) ucpUnsignedKey[ui];
450 vFindKeyValues(spJson, spIt, uipKey, uiLength, spValue);
454 vpReturn = (
void*)spIt;
475 void* vpReturn = NULL;
477 if((vpCtx == NULL) || (spJson->
vpValidate != s_vpJsonValid)){
481 vFindKeyValues(spJson, spIt, uipKey, uiLength, spValue);
502 void* vpReturn = NULL;
504 if((vpCtx == NULL) || (spJson->
vpValidate != s_vpJsonValid)){
508 vWalkCount(spJson, spValue);
517 vpReturn = (
void*)spIt;
531 void* vpReturn = NULL;
533 if((vpCtx == NULL) || (spJson->
vpValidate != s_vpJsonValid)){
539 if(spValue->uiChildCount){
542 spIt->
uiCount = spValue->uiChildCount;
544 for(; ui < spValue->uiChildCount; ui++){
545 spIt->
sppValues[ui] = spValue->sppChildren[ui];
547 vpReturn = (
void*)spIt;
615 if((vpIteratorCtx == NULL) || (spIt->
vpValidate != s_vpIteratorValid)){
628 json_value* spReturn = NULL;
630 if((vpIteratorCtx == NULL) || (spIt->
vpValidate != s_vpIteratorValid)){
648 json_value* spReturn = NULL;
650 if((vpIteratorCtx == NULL) || (spIt->
vpValidate != s_vpIteratorValid)){
672 json_value* spReturn = NULL;
674 if((vpIteratorCtx == NULL) || (spIt->
vpValidate != s_vpIteratorValid)){
693 if((vpIteratorCtx == NULL) || (spIt->
vpValidate != s_vpIteratorValid)){
710 static void vParseInput(
json* spJson) {
756 for (ui = 0; ui < uiCharCount; ui++) {
760 memset((
void*) &sInput, 0,
sizeof(sInput));
762 sInput.uiInputLength = uiCharCount;
763 sInput.uiStartRule = 0;
764 sInput.vpUserData = (
void*) spJson;
781 static abool bKeyComp(
u32_phrase* spKey,
const uint32_t *uipKey, uint32_t uiLength){
785 for(; ui < uiLength; ui++){
795 static void vFindKeyValues(
json* spJson,
json_iterator* spIt,
const uint32_t *uipKey, uint32_t uiLength, json_value* spValue){
796 if(spValue->spKey && bKeyComp(spValue->spKey, uipKey, uiLength)){
800 json_value** sppChildren = spValue->sppChildren;
801 json_value** sppEnd = sppChildren + spValue->uiChildCount;
802 for (; sppChildren < sppEnd; sppChildren++) {
803 vFindKeyValues(spJson, spIt, uipKey, uiLength, *sppChildren);
807 static void vIndent(
aint uiIndent) {
809 for (; ui < uiIndent; ui++) {
825 const char* cpNextLine;
827 if (spValue->
spKey) {
832 printf(
"key: \"%s\"\n", cpStr);
835 printf(
"key: (some or all not printable ASCII)\n");
839 printf(
"%s", cpNextLine);
844 switch (spValue->
uiId) {
875 printf(
"string: \"%s\"\n", cpStr);
878 printf(
"string: (some or all not printable ASCII)\n");
882 printf(
"%s", cpNextLine);
895 printf(
"number: signed int: %"PRIiMAX
"\n", (intmax_t)
spNumber->
iSigned);
904 printf(
"literal: %s\n", s_cpTrue);
908 printf(
"literal: %s\n", s_cpFalse);
912 printf(
"literal: %s\n", s_cpNull);
915 snprintf(caBuf, 128,
"unknown record type ID: %"PRIuMAX
"", (
luint) spValue->
uiId);
920 static void vBreakIndent(
json* spJson,
aint uiIndent) {
924 for (ui = 0; ui < uiIndent; ui++) {
929 static void vPushObject(
json* spJson, json_value* spValue,
abool bArray) {
930 uint32_t uiOpen = bArray ? s_uiOpenSquare : s_uiOpenCurly;
931 uint32_t uiClose = bArray ? s_uiCloseSquare : s_uiCloseCurly;
936 for (ui = 0; ui < spValue->uiChildCount; ui++) {
941 vPushValue(spJson, spValue->sppChildren[ui]);
958 }
else if(uiChar == 0x22){
962 }
else if(uiChar >= 0 && uiChar < 0x20){
966 snprintf(caBuf, 64,
"%04X", uiChar);
967 uiChar = (uint32_t)caBuf[0];
969 uiChar = (uint32_t)caBuf[1];
971 uiChar = (uint32_t)caBuf[2];
973 uiChar = (uint32_t)caBuf[3];
975 }
else if(uiChar >= 0xD800 && uiChar < 0xDFFF){
977 XTHROW(spJson->
spException,
"string has code point value in surrogate pair range ([0xD800 - 0xDFFF])");
978 }
else if(uiChar > 0x10FFFF){
998 uint32_t* uip = uiBuf;
1002 *uip++ = (uint32_t) *cp++;
1008 static void vPushValue(
json* spJson, json_value* spValue) {
1012 if (spValue->spKey) {
1013 vPushString(spJson, spValue->spKey);
1019 vPushObject(spJson, spValue,
APG_FALSE);
1021 vPushObject(spJson, spValue,
APG_TRUE);
1023 switch (spValue->uiId) {
1025 vPushString(spJson, spValue->spString);
1028 vPushNumber(spJson, spValue->spNumber);
1045 static void vWalkCount(
json* spJson, json_value* spValue){
1047 switch(spValue->uiId){
1058 for(ui = 0; ui < spValue->uiChildCount; ui++){
1059 vWalkCount(spJson, spValue->sppChildren[ui]);
int64_t iSigned
If uiType = JSON_ID_SIGNED, the signed int value.
aint uiLineLength
The number of characters in the line, including the line end characters.
json_iterator * spJsonIteratorCtor(json *spJson)
Private function for internal object use only. Never called by the application.
double dFloat
If uiType = JSON_ID_FLOAT, the floating point value.
u32_phrase * spString
Pointer to the string value if uiId = JSON_ID_STRING.
void * vpParserCtor(exception *spException, void *vpParserInit)
The parser's constructor for file initialization data.
void * vpVecAscii
A scratch vector for constructing ASCII strings on the fly.
void * vpVecIterators
A vector of iterator context pointers remembered for destruction.
void * vpLinesCtor(exception *spEx, const char *cpInput, aint uiLength)
The lines object constructor.
aint uiSuccess
True (>0) if the input string was matched in its entirety, false (0) otherwise.
void * vpJsonChildren(void *vpCtx, json_value *spValue)
Initialize the iterator over the children of the given value as the parent node.
void vMemDtor(void *vpCtx)
Destroys a Memory component. Frees all memory allocated.
The object context. For intenrnal use only.
void * vpJsonFindKeyA(void *vpCtx, const char *cpKey, json_value *spValue)
Find JSON values with a specified ASCII key.
void * vpJsonReadFile(void *vpCtx, const char *cpFileName)
The JSON file reader.
A JSON interator object context.
The structure of a JSON number value.
void vVecDtor(void *vpCtx)
The vector component destructor.
uint32_t uiLength
The number of integers in the array.
frame * spCurrentFrame
Points to the current stack frame.
void vJsonDisplayInput(void *vpCtx, abool bShowLines)
Display the input JSON byte stream.
exception * spException
Pointer to the exception structure for reporting errors to the application catch block.
void vExContext()
Handles bad context pointers.
json_value * spValues
an array of absolute values.
uint_fast8_t achar
achar is the type for the parser's alphabet characters.
void * vpConvCtor(exception *spEx)
The data conversion object constructor.
aint uiCurrentDepth
Used to keep track of the current tree depth for display of the tree of values.
Each value is a node in the parse tree.
#define JSON_ID_STRING
String value.
json * spJson
Pointer to the parent JSON object context.
const uint32_t * uipPhrase
Pointer to an array of 32-bit unsigned integers.
#define XTHROW(ctx, msg)
Exception throw macro.
void * vpConv
Context pointer for a conversion object.
#define JSON_ID_ARRAY
Array value.
This is the "relative" value developed during parsing.
void * vpJsonFindKeyU(void *vpCtx, const uint32_t *uipKey, aint uiLength, json_value *spValue)
Find JSON values with the specified 32-bit Unicode key.
uint_fast32_t aint
The APG parser's unsigned integer type.
aint uiId
The type of value. One of.
#define JSON_ID_FALSE
Literal value is false.
Defines the input string and other configuration parameters for the parser,.
#define JSON_ID_OBJECT
Object value.
void * vpVecInput
The UTF-8-encoded input byte stream. BOM, if any, removed.
aint uiDataType
[in] One of the encoding type identifiers, UTF_8, etc.
abool bFirstNode
Set to true before each call to sJsonWrite() to prevent writing a key for the first node of a sub-tre...
void * vpMemAlloc(void *vpCtx, aint uiBytes)
Allocates memory.
abool bHasFrac
A working value signaling presence of fractional value for a number value.
aint uiVecLen(void *vpCtx)
Get the vector length. That is, the number of elements on the vector.
void * vpMem
Pointer to a memory object used for all memory allocations.
void * vpVecCtor(void *vpMem, aint uiElementSize, aint uiInitialAlloc)
The vector object constructor.
Defines the output data type, location, length and whether or not to preface with a Byte Order Mark (...
#define JSON_ID_TRUE
Literal value is true.
void vJsonDisplayValue(void *vpCtx, json_value *spValue, aint uiDepth)
Display a value and optionally the values in the branch below, if any.
The parser's final state.
uint32_t uiChar
A working value to hold the value of a single character. Higher level rules will move it to vpVecChar...
A structure to describe the type and location of a caught exception.
void vMemFree(void *vpCtx, const void *vpData)
Free memory previously allocated with vpMemAlloc().
abool bJsonValidate(void *vpCtx)
Validate a JSON context pointer.
This is the "relative" string developed during parsing.
uint8_t * ucpJsonWrite(void *vpCtx, json_value *spValue, aint *uipCount)
Converts a sub-tree of values into UTF-8 byte stream of JSON text.
aint uiStringCount
The number of strings in the array.
uintmax_t luint
luint is used to cast integers suitable for the %"PRIuMAX" printf format.
json_value * spJsonIteratorFirst(void *vpIteratorCtx)
Find the first value in the list represented by this iterator.
aint uiChildCount
The number of child values if uiId is JSON_ID_OBJECT or JSON_ID_ARRAY.
aint uiLineIndex
The zero-based line index.
abool bExValidate(exception *spException)
Test an exception structure for validity.
const void * vpValidate
Used by the memory object to validate the exception structure.
void * vpVecFirst(void *vpCtx)
Get the first element one the vector. The vector is not altered.
#define JSON_ID_FLOAT
Number value is a double floating point number.
void * vpVecPushn(void *vpCtx, void *vpElement, aint uiCount)
Adds one or more elements to the end of the array.
aint uiMaxDepth
The maximum tree depth of values to display.
json_number * spNumber
Pointer to the number value if uiId = JSON_ID_NUMBER.
Defines the characteristics of a single line.
Private JSON component header file.
void * vpMemCtor(exception *spException)
Construct a memory component.
aint uiValueCount
The number of values in the array.
void * vpVecScratch32
A vector of 32-bit integer scratch space.
json_value * spJsonIteratorNext(void *vpIteratorCtx)
Find the next value in the list represented by this iterator.
void * vpVecOutput
Vector of 32-bit code points for generating output of value tree to JSON-text.
void vConvEncode(void *vpCtx, conv_dst *spDst)
Encode the 32-bit Unicode code points to a byte stream.
void * vpLines
pointer to a lines object context
aint uiCount
The number of pointers in the list.
aint uiJsonIteratorCount(void *vpIteratorCtx)
Find the number of values in the list represented by this iterator.
json_value ** sppValues
List of pointers to values.
achar * acpInput
Buffer to hold the input converted from uint8_t to achar units.
line * spLinesFirst(void *vpCtx)
Initialize an iterator over the lines.
u32_phrase * spKey
Points to the associated key string if this is a member of a JSON object. Otherwise,...
void vLinesDtor(void *vpCtx)
The lines object destructor.
void vParserDtor(void *vpCtx)
Clears the parser component's context and frees all heap memory associated with this parser.
void vJsonIteratorDtor(void *vpIteratorCtx)
The JSON iterator destructor.
uint64_t uiUnsigned
If uiType = JSON_ID_UNSIGNED, the unsigned int value.
#define UTF_8
Data type macro for UTF-8 encoding/decoding.
const void * vpValidate
Must be the "magic number" to be a valid context.
const void * vpValidate
Must be the "magic number" to be a valid context.
aint uiDataLen
[out] Number of bytes in the byte stream.
void * vpJsonReadArray(void *vpCtx, uint8_t *ucpData, aint uiDataLen)
The JSON array reader.
uint8_t abool
abool is the APG bool type.
Header file for the JSON component. Defines API prototypes.
#define JSON_ID_SIGNED
Number value is a 64-bit signed integer.
void * vpJsonCtor(exception *spEx)
The JSON constructor.
void vJsonDtor(void *vpCtx)
The JSON Parser component destructor.
#define JSON_ID_UNSIGNED
Number value is a 64-bit unsigned integer.
void * vpFmt
Pointer to a hexdump-style formatter object.
json_value * spJsonIteratorPrev(void *vpIteratorCtx)
Find the prev value in the list represented by this iterator.
struct json_value_tag ** sppChildren
Points to a list of child value pointers if uiId is JSON_ID_OBJECT or JSON_ID_ARRAY.
aint uiType
Identifies the number type. One of.
aint uiWalkCount
An accumulator for counting sub-tree nodes and child nodes.
abool bHasMinus
A working value signaling a minus sign for a number value.
Defines a pointer to an array of 32-bit unsigned integers plus its length. Typically needed by Unicod...
#define JSON_ID_NULL
Literal value is null.
void * vpJsonTree(void *vpCtx, json_value *spValue)
Initialize the iterator to walk a value tree.
The structure of a JSON value.
void vConvDtor(void *vpCtx)
Conversion object destructor.
json_value * spJsonIteratorLast(void *vpIteratorCtx)
Find the last value in the list represented by this iterator.
FILE * spIn
File I/O handle for the input file. Maintained here so that it can be closed in the destructor if nec...
void * vpParser
Pointer to the parser context if exception thrown during parsing.
uint8_t * ucpData
[out] Pointer to the output byte stream. Valid until another function call on the context handle.
void * vpVecPush(void *vpCtx, void *vpElement)
Adds one element to the end of the array.
aint uiCurrent
The current iterator value index.
void vConvUseCodePoints(void *vpCtx, uint32_t *uipSrc, aint uiSrcLen)
Insert a stream of 32-bit Unicode code points as the intermediate data.
#define JSON_ID_NUMBER
Number value.
void vVecClear(void *vpCtx)
Clears all used elements in a vector component.
void vUtilPrintParserState(parser_state *spState)
Display the parser state in human-readable format to stdout.
aint uiCharIndex
The zero-based index of the first character of the line.
void vJsonGrammarRuleCallbacks(void *vpParserCtx)
void vParserParse(void *vpCtx, parser_config *spConfig, parser_state *spState)
Parse an input string of alphabet characters.
aint uiLinesCount(void *vpCtx)
Returns the number of lines of text.
APG Version 7.0 is licensed under the
2-Clause BSD License,
an Open Source Initiative Approved License.