Анализ JSON с использованием Lemon (и Core Foundation)
Я пытаюсь написать простой парсер JSON, используя Lemon и Apple Core Foundation.
Вот код на данный момент:
%include {
#import <CoreFoundation/CoreFoundation.h>
#import "state.h" // struct ParserState { CFTypeRef result; };
#import "tuple.h" // struct Tuple { CFTypeRef one; CFTypeRef two; };
}
%start_symbol json
%token_type { CFTypeRef }
%token_prefix T
%extra_argument { ParserStateRef state }
%type simple_value { CFTypeRef }
%type member { TupleRef }
%type members { CFMutableDictionaryRef }
%type object { CFMutableDictionaryRef }
%type array { CFMutableArrayRef }
simple_value(A) ::= STRING(B). { A = B; }
simple_value(A) ::= INT(B). { A = B; }
simple_value(A) ::= FLOAT(B). { A = B; }
simple_value(A) ::= FALSE. { A = kCFBooleanFalse; }
simple_value(A) ::= TRUE. { A = kCFBooleanTrue; }
simple_value(A) ::= NULL. { A = kCFNull; }
member(A) ::= STRING(B) COLON simple_value(C). {
A = TupleCreate(B,C);
}
member ::= STRING COLON object.
member ::= STRING COLON array.
members(A) ::= member(B). {
A = CFDictionaryCreateMutable(kCFAllocatorDefault,0,&kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(A, B->first, B->second);
CFRelease(B->first);
CFRelease(B->second);
TupleRelease(B);
}
members(A) ::= members(B) COMMA member(C). {
CFDictionarySetValue(B, C->first, C->second);
CFRelease(C->first);
CFRelease(C->second);
TupleRelease(C);
A = B;
}
values ::= value.
values ::= values COMMA value.
object(A) ::= LCB RCB. {
/* THIS NEVER GETS CALLED */
A = CFDictionaryCreateMutable(kCFAllocatorDefault,0,&kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks);
}
object(A) ::= LCB members(B) RCB. {
/* THIS NEVER GETS CALLED */
A = B;
}
array ::= LSB RSB.
array ::= LSB values RSB.
value ::= array.
value ::= object.
value ::= simple_value.
json ::= object(A). { state->result = A; }
json ::= array.
С простым JSON, как это
{ \"hello\" : \"world\" }
Я не могу пройти мимо правила членов (в этот момент словарь настроен правильно).
Правило объекта никогда не вызывается, и объект json::= делает то же самое!
Я делаю что-то глупое?
Любой вклад будет оценен!
1 ответ
Вы должны вызвать функцию Parser(...) с нулевым значением для второго параметра, когда поток токенов исчерпан.
Информация от: https://www.sqlite.org/src/doc/trunk/doc/lemon.html
01 ParseTree *ParseFile(const char *zFilename){
02 Tokenizer *pTokenizer;
03 void *pParser;
04 Token sToken;
05 int hTokenId;
06 ParserState sState;
07
08 pTokenizer = TokenizerCreate(zFilename);
09 pParser = ParseAlloc( malloc );
10 InitParserState(&sState);
11 while( GetNextToken(pTokenizer, &hTokenId, &sToken) ){
12 Parse(pParser, hTokenId, sToken, &sState);
13 }
14 Parse(pParser, 0, sToken, &sState);
15 ParseFree(pParser, free );
16 TokenizerFree(pTokenizer);
17 return sState.treeRoot;
18 }
См. Строку 14. Он говорит парсеру, что он не должен ожидать больше токенов и может выполнять оставшиеся правила.
По сути, программа должна использовать парсер, сгенерированный Lemon, сначала создать парсер, а затем отправить ему множество токенов, полученных путем токенизации входного источника. Когда достигнут конец ввода, подпрограмма Parse() должна быть вызвана в последний раз с типом токена 0. Этот шаг необходим, чтобы сообщить парсеру, что конец ввода достигнут. Наконец, мы освобождаем память, используемую анализатором, вызывая ParseFree().