Statement* Parser::readValue() { switch(currentToken.id) { case Token::not_: { UnaryStatement* statement = new UnaryStatement(*includeFile); statement->operation = currentToken.id; nextToken(); statement->operand = readValue(); return statement; } case Token::leftParenthesis: { nextToken(); Statement* statement = readExpression(); expectToken(Token::rightParenthesis); return statement; } case Token::leftBrace: { nextToken(); BlockStatement* statements = new BlockStatement(*includeFile); while(currentToken.id != Token::rightBrace) { if(currentToken.id == Token::eof) expectToken(Token::rightBrace); statements->statements.append(readStatement()); } nextToken(); return statements; } case Token::string: if(currentToken.value == "true") { nextToken(); StringStatement* statement = new StringStatement(*includeFile); statement->value = "true"; return statement; } else if(currentToken.value == "false") { nextToken(); return new StringStatement(*includeFile); } else { ReferenceStatement* statement = new ReferenceStatement(*includeFile); readString(statement->variable); return statement; } default: // quotedString { StringStatement* statement = new StringStatement(*includeFile); readString(statement->value); return statement; } } }
void JsonSerializer::deserializeArrayBegin(const char* label) { deserializeLabel(label); expectToken('['); m_is_first_in_block = true; deserializeToken(); }
void JsonSerializer::deserializeLabel(const char* label) { if (!m_is_first_in_block) { expectToken(','); deserializeToken(); } else { m_is_first_in_block = false; } if (!m_is_string_token) { ErrorProxy(*this).log() << "Unexpected token \"" << string(m_token, m_token_size, m_allocator) << "\", expected string."; deserializeToken(); } if (compareStringN(label, m_token, m_token_size) != 0) { ErrorProxy(*this).log() << "Unexpected label \"" << string(m_token, m_token_size, m_allocator) << "\", expected \"" << label << "\"."; deserializeToken(); } deserializeToken(); if (m_is_string_token || m_token_size != 1 || m_token[0] != ':') { ErrorProxy(*this).log() << "Unexpected label \"" << string(m_token, m_token_size, m_allocator) << "\", expected \"" << label << "\"."; deserializeToken(); } deserializeToken(); }
void JsonSerializer::nextArrayItem() { if (!m_is_first_in_block) { expectToken(','); deserializeToken(); } }
/* ====================== ReadActionNode Parses and creates an AIGenericNode_t with the type ACTION_NODE from a token list The token list pointer is modified to point to the beginning of the next node text block after reading An action node has the form: action name( p1, p2, ... ) Where name defines the action to execute, and the parameters are surrounded by parenthesis ====================== */ AIGenericNode_t *ReadActionNode( pc_token_list **tokenlist ) { pc_token_list *current = *tokenlist; pc_token_list *parenBegin; AIActionNode_t *ret = nullptr; AIActionNode_t node; struct AIActionMap_s *action = nullptr; if ( !expectToken( "action", ¤t, true ) ) { return nullptr; } if ( !current ) { Log::Warn( "Unexpected end of file after line %d", (*tokenlist)->token.line ); return nullptr; } action = (struct AIActionMap_s*) bsearch( current->token.string, AIActions, ARRAY_LEN( AIActions ), sizeof( *AIActions ), cmdcmp ); if ( !action ) { Log::Warn( "%s on line %d is not a valid action", current->token.string, current->token.line ); *tokenlist = current; return nullptr; } parenBegin = current->next; memset( &node, 0, sizeof( node ) ); BotInitNode( ACTION_NODE, action->run, &node ); // allow dropping of parenthesis if we don't require any parameters if ( action->minparams == 0 && parenBegin->token.string[0] != '(' ) { ret = allocNode( AIActionNode_t ); memcpy( ret, &node, sizeof( node ) ); *tokenlist = parenBegin; return ( AIGenericNode_t * ) ret; } node.params = parseFunctionParameters( ¤t, &node.nparams, action->minparams, action->maxparams ); if ( !node.params && action->minparams > 0 ) { return nullptr; } // create the action node ret = allocNode( AIActionNode_t ); memcpy( ret, &node, sizeof( *ret ) ); *tokenlist = current; return ( AIGenericNode_t * ) ret; }
void JsonSerializer::deserializeArrayComma() { if (m_is_first_in_block) { m_is_first_in_block = false; } else { expectToken(','); deserializeToken(); } }
void JsonSerializer::deserializeLabel(char* label, int max_length) { if (!m_is_first_in_block) { expectToken(','); deserializeToken(); } else { m_is_first_in_block = false; } if (!m_is_string_token) { ErrorProxy(*this).log() << "Unexpected token \"" << string(m_token, m_token_size, m_allocator) << "\", expected string."; deserializeToken(); } copyNString(label, max_length, m_token, m_token_size); deserializeToken(); expectToken(':'); deserializeToken(); }
/* ====================== ReadNodeList Parses and creates an AINodeList_t from a token list The token list pointer is modified to point to the beginning of the next node text block after reading ====================== */ AIGenericNode_t *ReadNodeList( pc_token_list **tokenlist ) { AINodeList_t *list; pc_token_list *current = *tokenlist; if ( !expectToken( "{", ¤t, true ) ) { return nullptr; } list = allocNode( AINodeList_t ); while ( Q_stricmp( current->token.string, "}" ) ) { AIGenericNode_t *node = ReadNode( ¤t ); if ( node && list->numNodes >= MAX_NODE_LIST ) { Log::Warn( "Max selector children limit exceeded at line %d", (*tokenlist)->token.line ); FreeNode( node ); FreeNodeList( list ); *tokenlist = current; return nullptr; } else if ( node ) { list->list[ list->numNodes ] = node; list->numNodes++; } if ( !node ) { *tokenlist = current; FreeNodeList( list ); return nullptr; } if ( !current ) { *tokenlist = current; return ( AIGenericNode_t * ) list; } } *tokenlist = current->next; return ( AIGenericNode_t * ) list; }
static AIExpType_t *Primary( pc_token_list **list ) { pc_token_list *current = *list; AIExpType_t *tree = nullptr; if ( isUnaryOp( opTypeFromToken( ¤t->token ) ) ) { AIExpType_t *t; AIOp_t *op = newOp( current ); *list = current->next; t = ReadConditionExpression( list, op->opType ); if ( !t ) { Log::Warn( "Missing right operand for %s on line %d", opTypeToString( op->opType ), current->token.line ); FreeOp( op ); return nullptr; } tree = makeExpression( op, t, nullptr ); } else if ( current->token.string[0] == '(' ) { *list = current->next; tree = ReadConditionExpression( list, OP_NONE ); if ( !expectToken( ")", list, true ) ) { return nullptr; } } else if ( current->token.type == tokenType_t::TT_NUMBER ) { tree = ( AIExpType_t * ) newValueLiteral( list ); } else if ( current->token.type == tokenType_t::TT_NAME ) { tree = ( AIExpType_t * ) newValueFunc( list ); } else { Log::Warn( "token %s on line %d is not valid", current->token.string, current->token.line ); } return tree; }
int main( int argc, char *argv[] ) { // Open the program's source. if ( argc != 2 ) usage(); FILE *fp = fopen( argv[ 1 ], "r" ); if ( !fp ) { fprintf( stderr, "Can't open file: %s\n", argv[ 1 ] ); usage(); } // Parse the whole program source into an expression object. // The parser uses a one-token lookahead to help parsing compound expressions. char tok[ MAX_TOKEN + 1 ]; Expr *expr = parse( expectToken( tok, fp ), fp ); // If this is a legal input, there shouldn't be any extra tokens at the end. if ( nextToken( tok, fp ) ) { fprintf( stderr, "line %d: unexpected token \"%s\"\n", linesRead(), tok ); exit( EXIT_FAILURE ); } fclose( fp ); // Run the program. Context *ctxt = makeContext(); char *result = expr->eval( expr, ctxt ); // Everything evaluates to a dynamically allocated string, but we don't // do anything with the one out of the top-level expression. free( result ); // We're done, free everything. freeContext( ctxt ); expr->destroy( expr ); return EXIT_SUCCESS; }
AIGenericNode_t *ReadBehaviorTreeInclude( pc_token_list **tokenlist ) { pc_token_list *first = *tokenlist; pc_token_list *current = first; AIBehaviorTree_t *behavior; if ( !expectToken( "behavior", ¤t, true ) ) { return nullptr; } if ( !current ) { Log::Warn( "Unexpected end of file after line %d", first->token.line ); *tokenlist = current; return nullptr; } behavior = ReadBehaviorTree( current->token.string, currentList ); if ( !behavior ) { Log::Warn( "Could not load behavior %s on line %d", current->token.string, current->token.line ); *tokenlist = current->next; return nullptr; } if ( !behavior->root ) { Log::Warn( "Recursive behavior %s on line %d", current->token.string, current->token.line ); *tokenlist = current->next; return nullptr; } *tokenlist = current->next; return ( AIGenericNode_t * ) behavior; }
void JsonSerializer::deserializeObjectEnd() { expectToken('}'); m_is_first_in_block = false; deserializeToken(); }
void JsonSerializer::deserializeObjectBegin() { m_is_first_in_block = true; expectToken('{'); deserializeToken(); }
int HSPReadConfigFile(HSP *sp) { EnumHSPObject level[HSP_MAX_CONFIG_DEPTH + 5]; int depth = 0; level[depth] = HSPOBJ_HSP; // could have used something like bison to make a complete parser with // strict rules, but for simplicity we just allow the current object // to double as a state variable that determines what is allowed next. for(HSPToken *tok = readTokens(sp); tok; tok = tok->nxt) { if(depth > HSP_MAX_CONFIG_DEPTH) { // depth overrun parseError(sp, tok, "too many '{'s", ""); return NO; } else if(tok->stok == HSPTOKEN_ENDOBJ) { // end of level, pop the stack if(depth > 0) --depth; else { parseError(sp, tok, "too many '}'s ", ""); return NO; } } else switch(level[depth]) { case HSPOBJ_HSP: // must start by opening an sFlow object if((tok = expectToken(sp, tok, HSPTOKEN_SFLOW)) == NULL) return NO; if((tok = expectToken(sp, tok, HSPTOKEN_STARTOBJ)) == NULL) return NO; newSFlow(sp); level[++depth] = HSPOBJ_SFLOW; break; case HSPOBJ_SFLOW: switch(tok->stok) { case HSPTOKEN_DNSSD: if((tok = expectDNSSD(sp, tok)) == NULL) return NO; break; case HSPTOKEN_DNSSD_DOMAIN: if((tok = expectDNSSD_domain(sp, tok)) == NULL) return NO; break; case HSPTOKEN_COLLECTOR: if((tok = expectToken(sp, tok, HSPTOKEN_STARTOBJ)) == NULL) return NO; newCollector(sp->sFlow->sFlowSettings_file); level[++depth] = HSPOBJ_COLLECTOR; break; case HSPTOKEN_SAMPLING: case HSPTOKEN_PACKETSAMPLINGRATE: if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->samplingRate, 0, 65535)) == NULL) return NO; break; case HSPTOKEN_POLLING: case HSPTOKEN_COUNTERPOLLINGINTERVAL: if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->pollingInterval, 0, 300)) == NULL) return NO; break; case HSPTOKEN_AGENTIP: if((tok = expectIP(sp, tok, &sp->sFlow->agentIP, NULL)) == NULL) return NO; break; case HSPTOKEN_AGENT: if((tok = expectDevice(sp, tok, &sp->sFlow->agentDevice)) == NULL) return NO; break; case HSPTOKEN_SUBAGENTID: if((tok = expectInteger32(sp, tok, &sp->sFlow->subAgentId, 0, HSP_MAX_SUBAGENTID)) == NULL) return NO; break; case HSPTOKEN_UUID: if((tok = expectUUID(sp, tok, sp->uuid)) == NULL) return NO; break; case HSPTOKEN_HEADERBYTES: if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->headerBytes, 0, HSP_MAX_HEADER_BYTES)) == NULL) return NO; break; case HSPTOKEN_ULOGGROUP: if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->ulogGroup, 1, 32)) == NULL) return NO; break; case HSPTOKEN_ULOGPROBABILITY: if((tok = expectDouble(sp, tok, &sp->sFlow->sFlowSettings_file->ulogProbability, 0.0, 1.0)) == NULL) return NO; break; default: parseError(sp, tok, "unexpected sFlow setting", ""); return NO; break; } break; case HSPOBJ_COLLECTOR: { HSPCollector *col = sp->sFlow->sFlowSettings_file->collectors; switch(tok->stok) { case HSPTOKEN_IP: if((tok = expectIP(sp, tok, &col->ipAddr, (struct sockaddr *)&col->sendSocketAddr)) == NULL) return NO; break; case HSPTOKEN_UDPPORT: if((tok = expectInteger32(sp, tok, &col->udpPort, 1, 65535)) == NULL) return NO; break; default: parseError(sp, tok, "unexpected collector setting", ""); return NO; break; } } break; default: parseError(sp, tok, "unexpected state", ""); } } // OK we consumed all the tokens, but we still need to run some sanity checks to make sure // we have a usable configuration... int parseOK = YES; if(sp->sFlow == NULL) { myLog(LOG_ERR, "parse error in %s : sFlow not found", sp->configFile); parseOK = NO; } else { //////////////////////// sFlow ///////////////////////// if(sp->sFlow->agentIP.type == 0) { // it may have been defined as agent=<device> if(sp->sFlow->agentDevice) { SFLAdaptor *ad = adaptorListGet(sp->adaptorList, sp->sFlow->agentDevice); if(ad && ad->ipAddr.addr) { sp->sFlow->agentIP.type = SFLADDRESSTYPE_IP_V4; sp->sFlow->agentIP.address.ip_v4 = ad->ipAddr; } } } if(sp->sFlow->agentIP.type == 0) { // nae luck - try to automatically choose the first non-loopback IP address for(uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) { SFLAdaptor *adaptor = sp->adaptorList->adaptors[i]; // only the non-loopback devices should be listed here, so just take the first if(adaptor && adaptor->ipAddr.addr) { sp->sFlow->agentIP.type = SFLADDRESSTYPE_IP_V4; sp->sFlow->agentIP.address.ip_v4 = adaptor->ipAddr; // fill in the device that we picked too sp->sFlow->agentDevice = strdup(adaptor->deviceName); break; } } } if(sp->sFlow->agentIP.type == SFLADDRESSTYPE_IP_V4 && sp->sFlow->agentDevice == NULL) { // try to fill in the device field too (because we need to give that one to open vswitch). for(uint32_t i = 0; i < sp->adaptorList->num_adaptors; i++) { SFLAdaptor *adaptor = sp->adaptorList->adaptors[i]; if(adaptor && (adaptor->ipAddr.addr == sp->sFlow->agentIP.address.ip_v4.addr)) { sp->sFlow->agentDevice = strdup(adaptor->deviceName); break; } } } if(sp->sFlow->agentIP.type == 0) { // still no agentIP. That's a showstopper. myLog(LOG_ERR, "parse error in %s : agentIP not defined", sp->configFile); parseOK = NO; } if(sp->sFlow->sFlowSettings_file->numCollectors == 0 && sp->DNSSD == NO) { myLog(LOG_ERR, "parse error in %s : DNS-SD is off and no collectors are defined", sp->configFile); parseOK = NO; } for(HSPCollector *coll = sp->sFlow->sFlowSettings_file->collectors; coll; coll = coll->nxt) { //////////////////////// collector ///////////////////////// if(coll->ipAddr.type == 0) { myLog(LOG_ERR, "parse error in %s : collector has no IP", sp->configFile); parseOK = NO; } } if(sp->sFlow->sFlowSettings_file->ulogProbability > 0) { sp->sFlow->sFlowSettings_file->ulogSamplingRate = (uint32_t)(1.0 / sp->sFlow->sFlowSettings_file->ulogProbability); } } return parseOK; }
void JsonSerializer::deserializeArrayEnd() { expectToken(']'); m_is_first_in_block = false; deserializeToken(); }
void JsonSerializer::deserializeArrayBegin() { expectToken('['); m_is_first_in_block = true; deserializeToken(); }
/** Parse with one token worth of look-ahead, return the expression object representing the syntax parsed. @param tok next token from the input. @param fp file subsequent tokens are being read from. @return the expression object constructed from the input. */ Expr *parse( char *tok, FILE *fp ) { // Create a literal token for anything that looks like a number. { long dummy; int pos; // See if the whole token parses as a long int. if ( sscanf( tok, "%ld%n", &dummy, &pos ) == 1 && pos == strlen( tok ) ) { // Copy the literal to a dynamically allocated string, since makeLiteral wants // a string it can keep. char *str = (char *) malloc( strlen( tok ) + 1 ); return makeLiteral( strcpy( str, tok ) ); } } // Create a literal token for a quoted string, without the quotes. if ( tok[ 0 ] == '"' ) { // Same as above, make a dynamically allocated copy of the token that the literal // expression can keep as long as at wants to. int len = strlen( tok ); char *str = (char *) malloc( len - 1 ); strncpy( str, tok + 1, len - 2 ); str[ len - 2 ] = '\0'; return makeLiteral( str ); } // Handle compound statements if ( strcmp( tok, "{" ) == 0 ) { int len = 0; int cap = INITIAL_CAPACITY; Expr **eList = (Expr **) malloc( cap * sizeof( Expr * ) ); // Keep parsing subexpressions until we hit the closing curly bracket. while ( strcmp( expectToken( tok, fp ), "}" ) != 0 ) { if ( len >= cap ) eList = (Expr **) realloc( eList, ( cap *= 2 ) * sizeof( Expr * ) ); eList[ len++ ] = parse( tok, fp ); } return makeCompound( eList, len ); } // Handle language operators (reserved words) if ( strcmp( tok, "print" ) == 0 ) { // Parse the one argument to print, and create a print expression. Expr *arg = parse( expectToken( tok, fp ), fp ); return makePrint( arg ); } if ( strcmp( tok, "set" ) == 0 ) { // Parse the two operands, then make a set expression with them. char *str = expectToken( tok, fp ); int len = strlen( str ); char *name = (char *) malloc( len + 1 ); strcpy( name, str ); name[ len ] = '\0'; if ( !isalpha(name[0]) || strlen( name ) > MAX_VAR || strchr( name, LEFT_BRACKET ) || strchr( name, RIGHT_BRACKET ) || strchr( name, POUND ) ) { // Complain if we can't make sense of the variable. fprintf( stderr, "line %d: invalid variable name \"%s\"\n", linesRead(), name ); exit( EXIT_FAILURE ); } Expr *expr = parse( expectToken( tok, fp ), fp ); Expr *set = makeSet ( name, expr ); free(name); return set; } if ( strcmp( tok, "add" ) == 0 ) { // Parse the two operands, then make an add expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeAdd( op1, op2 ); } if ( strcmp( tok, "sub" ) == 0 ) { // Parse the two operands, then make a sub expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeSub( op1, op2 ); } if ( strcmp( tok, "mul" ) == 0 ) { // Parse the two operands, then make a mul expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeMul( op1, op2 ); } if ( strcmp( tok, "div" ) == 0 ) { // Parse the two operands, then make a div expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeDiv ( op1, op2 ); } if ( strcmp( tok, "equal" ) == 0 ) { // Parse the two operands, then make an equal expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeEqual ( op1, op2 ); } if ( strcmp( tok, "less" ) == 0 ) { // Parse the two operands, then make a less expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeLess ( op1, op2 ); } if ( strcmp( tok, "not" ) == 0 ) { // Parse the operand, then make a not expression with it. Expr *op = parse( expectToken( tok, fp ), fp ); return makeNot ( op ); } if ( strcmp( tok, "and" ) == 0 ) { // Parse the two operands, then make an and expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeAnd ( op1, op2 ); } if ( strcmp( tok, "or" ) == 0 ) { // Parse the two operands, then make an or expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeOr ( op1, op2 ); } if ( strcmp( tok, "if" ) == 0 ) { // Parse the two operands, then make an if expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeIf ( op1, op2 ); } if ( strcmp( tok, "while" ) == 0 ) { // Parse the two operands, then make a while expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeWhile ( op1, op2 ); } if ( strcmp( tok, "concat" ) == 0 ) { // Parse the two operands, then make a concatenation expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); return makeConcat ( op1, op2 ); } if ( strcmp( tok, "substr" ) == 0 ) { // Parse the three operands, then make a substring expression with them. Expr *op1 = parse( expectToken( tok, fp ), fp ); Expr *op2 = parse( expectToken( tok, fp ), fp ); Expr *op3 = parse( expectToken( tok, fp ), fp ); return makeSubstr ( op1, op2, op3 ); } // Handle variables if ( isalpha(tok[0]) && strlen( tok ) <= MAX_VAR && !strchr( tok, LEFT_BRACKET ) && !strchr( tok, RIGHT_BRACKET ) && !strchr( tok, POUND ) ) { // Parse the variable name and make a variable expression. char *str = tok; int len = strlen( str ); char *name = (char *) malloc( len + 1 ); strcpy( name, str ); name[ len ] = '\0'; Expr *var = makeVariable( name ); free(name); return var; } // Complain if we can't make sense of the token. fprintf( stderr, "line %d: invalid token \"%s\"\n", linesRead(), tok ); exit( EXIT_FAILURE ); // Never reached. return NULL; }
static AIValue_t *parseFunctionParameters( pc_token_list **list, int *nparams, int minparams, int maxparams ) { pc_token_list *current = *list; pc_token_list *parenBegin = current->next; pc_token_list *parenEnd; pc_token_list *parse; AIValue_t *params = nullptr; int numParams = 0; // functions should always be proceeded by a '(' if they have parameters if ( !expectToken( "(", &parenBegin, false ) ) { *list = current; return nullptr; } // find the end parenthesis around the function's args parenEnd = findCloseParen( parenBegin, nullptr ); if ( !parenEnd ) { Log::Warn( "could not find matching ')' for '(' on line %d", parenBegin->token.line ); *list = parenBegin->next; return nullptr; } // count the number of parameters parse = parenBegin->next; while ( parse != parenEnd ) { if ( parse->token.type == tokenType_t::TT_NUMBER || parse->token.type == tokenType_t::TT_STRING ) { numParams++; } else if ( parse->token.string[ 0 ] != ',' ) { Log::Warn( "Invalid token %s in parameter list on line %d", parse->token.string, parse->token.line ); *list = parenEnd->next; // skip invalid function expression return nullptr; } parse = parse->next; } // warn if too many or too few parameters if ( numParams < minparams ) { Log::Warn( "too few parameters for %s on line %d", current->token.string, current->token.line ); *list = parenEnd->next; return nullptr; } if ( numParams > maxparams ) { Log::Warn( "too many parameters for %s on line %d", current->token.string, current->token.line ); *list = parenEnd->next; return nullptr; } *nparams = numParams; if ( numParams ) { // add the parameters params = ( AIValue_t * ) BG_Alloc( sizeof( *params ) * numParams ); numParams = 0; parse = parenBegin->next; while ( parse != parenEnd ) { if ( parse->token.type == tokenType_t::TT_NUMBER || parse->token.type == tokenType_t::TT_STRING ) { params[ numParams ] = AIBoxToken( &parse->token ); numParams++; } parse = parse->next; } } *list = parenEnd->next; return params; }
AIGenericNode_t *ReadDecoratorNode( pc_token_list **list ) { pc_token_list *current = *list; struct AIDecoratorMap_s *dec; AIDecoratorNode_t node; AIDecoratorNode_t *ret; pc_token_list *parenBegin; if ( !expectToken( "decorator", ¤t, true ) ) { return nullptr; } if ( !current ) { Log::Warn( "Unexpected end of file after line %d", (*list)->token.line ); *list = current; return nullptr; } dec = (struct AIDecoratorMap_s*) bsearch( current->token.string, AIDecorators, ARRAY_LEN( AIDecorators ), sizeof( *AIDecorators ), cmdcmp ); if ( !dec ) { Log::Warn( "%s on line %d is not a valid decorator", current->token.string, current->token.line ); *list = current; return nullptr; } parenBegin = current->next; memset( &node, 0, sizeof( node ) ); BotInitNode( DECORATOR_NODE, dec->run, &node ); // allow dropping of parenthesis if we don't require any parameters if ( dec->minparams == 0 && parenBegin->token.string[0] != '(' ) { ret = allocNode( AIDecoratorNode_t ); memcpy( ret, &node, sizeof( node ) ); *list = parenBegin; return ( AIGenericNode_t * ) ret; } node.params = parseFunctionParameters( ¤t, &node.nparams, dec->minparams, dec->maxparams ); if ( !node.params && dec->minparams > 0 ) { *list = current; return nullptr; } if ( !expectToken( "{", ¤t, true ) ) { *list = current; return nullptr; } node.child = ReadNode( ¤t ); if ( !node.child ) { Log::Warn( "Failed to parse child node of decorator on line %d", (*list)->token.line ); *list = current; return nullptr; } if ( !expectToken( "}", ¤t, true ) ) { *list = current; return nullptr; } // create the decorator node ret = allocNode( AIDecoratorNode_t ); memcpy( ret, &node, sizeof( *ret ) ); *list = current; return ( AIGenericNode_t * ) ret; }
/* ====================== ReadConditionNode Parses and creates an AIConditionNode_t from a token list The token list pointer is modified to point to the beginning of the next node text block A condition node has the form: condition [expression] { child node } or the form: condition [expression] [expression] can be any valid set of boolean operations and values ====================== */ AIGenericNode_t *ReadConditionNode( pc_token_list **tokenlist ) { pc_token_list *current = *tokenlist; AIConditionNode_t *condition; if ( !expectToken( "condition", ¤t, true ) ) { return nullptr; } condition = allocNode( AIConditionNode_t ); BotInitNode( CONDITION_NODE, BotConditionNode, condition ); condition->exp = ReadConditionExpression( ¤t, OP_NONE ); if ( !current ) { *tokenlist = current; Log::Warn( "Unexpected end of file" ); FreeConditionNode( condition ); return nullptr; } if ( !condition->exp ) { *tokenlist = current; FreeConditionNode( condition ); return nullptr; } if ( Q_stricmp( current->token.string, "{" ) ) { // this condition node has no child nodes *tokenlist = current; return ( AIGenericNode_t * ) condition; } current = current->next; condition->child = ReadNode( ¤t ); if ( !condition->child ) { Log::Warn( "Failed to parse child node of condition on line %d", (*tokenlist)->token.line ); *tokenlist = current; FreeConditionNode( condition ); return nullptr; } if ( !expectToken( "}", ¤t, true ) ) { *tokenlist = current; FreeConditionNode( condition ); return nullptr; } *tokenlist = current; return ( AIGenericNode_t * ) condition; }
int TokenStream::readInt() { Token t; expectToken(t,TT_INTEGER); return t.ival; }
int HSPReadConfigFile(HSP *sp) { EnumHSPObject level[HSP_MAX_CONFIG_DEPTH + 5]; int depth = 0; level[depth] = HSPOBJ_HSP; // could have used something like bison to make a complete parser with // strict rules, but for simplicity we just allow the current object // to double as a state variable that determines what is allowed next. for(HSPToken *tok = readTokens(sp); tok; tok = tok->nxt) { if(depth > HSP_MAX_CONFIG_DEPTH) { // depth overrun parseError(sp, tok, "too many '{'s", ""); return NO; } else if(tok->stok == HSPTOKEN_ENDOBJ) { // end of level, pop the stack if(depth > 0) --depth; else { parseError(sp, tok, "too many '}'s ", ""); return NO; } } else switch(level[depth]) { case HSPOBJ_HSP: // must start by opening an sFlow object if((tok = expectToken(sp, tok, HSPTOKEN_SFLOW)) == NULL) return NO; if((tok = expectToken(sp, tok, HSPTOKEN_STARTOBJ)) == NULL) return NO; newSFlow(sp); level[++depth] = HSPOBJ_SFLOW; break; case HSPOBJ_SFLOW: switch(tok->stok) { case HSPTOKEN_LOOPBACK: if((tok = expectLoopback(sp, tok)) == NULL) return NO; break; case HSPTOKEN_DNSSD: if((tok = expectDNSSD(sp, tok)) == NULL) return NO; break; case HSPTOKEN_DNSSD_DOMAIN: if((tok = expectDNSSD_domain(sp, tok)) == NULL) return NO; break; case HSPTOKEN_COLLECTOR: if((tok = expectToken(sp, tok, HSPTOKEN_STARTOBJ)) == NULL) return NO; newCollector(sp->sFlow->sFlowSettings_file); level[++depth] = HSPOBJ_COLLECTOR; break; case HSPTOKEN_SAMPLING: case HSPTOKEN_PACKETSAMPLINGRATE: if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->samplingRate, 0, 65535)) == NULL) return NO; break; case HSPTOKEN_POLLING: case HSPTOKEN_COUNTERPOLLINGINTERVAL: if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->pollingInterval, 0, 300)) == NULL) return NO; break; case HSPTOKEN_AGENTIP: if((tok = expectIP(sp, tok, &sp->sFlow->agentIP, NULL)) == NULL) return NO; sp->sFlow->explicitAgentIP = YES; break; case HSPTOKEN_AGENTCIDR: { HSPCIDR cidr = { 0 }; if((tok = expectCIDR(sp, tok, &cidr)) == NULL) return NO; addAgentCIDR(sp->sFlow->sFlowSettings_file, &cidr); } break; case HSPTOKEN_AGENT: if((tok = expectDevice(sp, tok, &sp->sFlow->agentDevice)) == NULL) return NO; sp->sFlow->explicitAgentDevice = YES; break; case HSPTOKEN_SUBAGENTID: if((tok = expectInteger32(sp, tok, &sp->sFlow->subAgentId, 0, HSP_MAX_SUBAGENTID)) == NULL) return NO; break; case HSPTOKEN_UUID: if((tok = expectUUID(sp, tok, sp->uuid)) == NULL) return NO; break; case HSPTOKEN_HEADERBYTES: if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->headerBytes, 0, HSP_MAX_HEADER_BYTES)) == NULL) return NO; break; case HSPTOKEN_ULOGGROUP: if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->ulogGroup, 1, 32)) == NULL) return NO; break; case HSPTOKEN_ULOGPROBABILITY: if((tok = expectDouble(sp, tok, &sp->sFlow->sFlowSettings_file->ulogProbability, 0.0, 1.0)) == NULL) return NO; break; case HSPTOKEN_JSONPORT: if((tok = expectInteger32(sp, tok, &sp->sFlow->sFlowSettings_file->jsonPort, 1025, 65535)) == NULL) return NO; break; default: // handle wildcards here - allow sampling.<app>=<n> and polling.<app>=<secs> if(tok->str && strncasecmp(tok->str, "sampling.", 9) == 0) { char *app = tok->str + 9; uint32_t sampling_n=0; if((tok = expectInteger32(sp, tok, &sampling_n, 0, 65535)) == NULL) return NO; setApplicationSampling(sp->sFlow->sFlowSettings_file, app, sampling_n); } else if(tok->str && strncasecmp(tok->str, "polling.", 8) == 0) { char *app = tok->str + 8; uint32_t polling_secs=0; if((tok = expectInteger32(sp, tok, &polling_secs, 0, 300)) == NULL) return NO; setApplicationPolling(sp->sFlow->sFlowSettings_file, app, polling_secs); } else { parseError(sp, tok, "unexpected sFlow setting", ""); return NO; } break; } break; case HSPOBJ_COLLECTOR: { HSPCollector *col = sp->sFlow->sFlowSettings_file->collectors; switch(tok->stok) { case HSPTOKEN_IP: if((tok = expectIP(sp, tok, &col->ipAddr, (struct sockaddr *)&col->sendSocketAddr)) == NULL) return NO; break; case HSPTOKEN_UDPPORT: if((tok = expectInteger32(sp, tok, &col->udpPort, 1, 65535)) == NULL) return NO; break; default: parseError(sp, tok, "unexpected collector setting", ""); return NO; break; } } break; default: parseError(sp, tok, "unexpected state", ""); } } // OK we consumed all the tokens, but we still need to run some sanity checks to make sure // we have a usable configuration... int parseOK = YES; if(sp->sFlow == NULL) { myLog(LOG_ERR, "parse error in %s : sFlow not found", sp->configFile); parseOK = NO; } else { if(sp->sFlow->sFlowSettings_file->numCollectors == 0 && sp->DNSSD == NO) { myLog(LOG_ERR, "parse error in %s : DNS-SD is off and no collectors are defined", sp->configFile); parseOK = NO; } for(HSPCollector *coll = sp->sFlow->sFlowSettings_file->collectors; coll; coll = coll->nxt) { //////////////////////// collector ///////////////////////// if(coll->ipAddr.type == 0) { myLog(LOG_ERR, "parse error in %s : collector has no IP", sp->configFile); parseOK = NO; } } if(sp->sFlow->sFlowSettings_file->ulogProbability > 0) { sp->sFlow->sFlowSettings_file->ulogSamplingRate = (uint32_t)(1.0 / sp->sFlow->sFlowSettings_file->ulogProbability); } } return parseOK; }