/* Functions for reading arrays. * * The code duplication between the get*Array() functions here is somewhat * alarming, but it's tricky to do something about it without the code becoming * an opaque mess of templates. * * At the very least, we'd need to make the tok.intVal(), tok.floatVal(), * tok.stringVal() into a template or overloaded functions taking a reference * so that the correct version could be called in a templated readArray(). * After that we'd still be left with the float case in which it's acceptable * for the token to be *either* an integer *or* a float. */ RibLexer::IntArray RibLexerImpl::getIntArray() { const RibToken& tok = m_tokenizer.get(); if(tok.type() != RibToken::ARRAY_BEGIN) tokenError("integer array", tok); std::vector<int>& buf = m_intArrayPool.getBuf(); bool parsing = true; while(parsing) { const RibToken& tok = m_tokenizer.get(); switch(tok.type()) { case RibToken::INTEGER: buf.push_back(tok.intVal()); break; case RibToken::ARRAY_END: parsing = false; break; default: tokenError("integer array element", tok); break; } } return toRiArray(buf); }
RibLexer::StringArray RibLexerImpl::getStringArray() { const RibToken& tok = m_tokenizer.get(); if(tok.type() != RibToken::ARRAY_BEGIN) tokenError("string array", tok); MultiStringBuffer& buf = m_stringArrayPool.getBuf(); bool parsing = true; while(parsing) { const RibToken& tok = m_tokenizer.get(); switch(tok.type()) { case RibToken::STRING: buf.push_back(tok.stringVal()); break; case RibToken::ARRAY_END: parsing = false; break; default: tokenError("string array element", tok); break; } } return toRiArray(buf); }
RibLexer::FloatArray RibLexerImpl::getFloatArray(int length) { std::vector<float>& buf = m_floatArrayPool.getBuf(); if(m_tokenizer.peek().type() == RibToken::ARRAY_BEGIN) { // Read an array in [ num1 num2 ... num_n ] format m_tokenizer.get(); // consume '[' bool parsing = true; while(parsing) { const RibToken& tok = m_tokenizer.get(); switch(tok.type()) { case RibToken::INTEGER: buf.push_back(tok.intVal()); break; case RibToken::FLOAT: buf.push_back(tok.floatVal()); break; case RibToken::ARRAY_END: parsing = false; break; default: tokenError("float array element", tok); break; } } if(length >= 0 && static_cast<int>(buf.size()) != length) { AQSIS_THROW_XQERROR(XqParseError, EqE_Syntax, "expected " << length << " float array componenets, got " << buf.size()); } } else if(length >= 0) { // Read an array in num1 num2 ... num_n format (ie, without the usual // array delimiters). for(int i = 0; i < length; ++i) buf.push_back(getFloat()); } else { tokenError("float array", m_tokenizer.get()); } return toRiArray(buf); }
int RibLexerImpl::getInt() { const RibToken& tok = m_tokenizer.get(); if(tok.type() != RibToken::INTEGER) tokenError("integer", tok); return tok.intVal(); }
tree * getFactor(token ** tokenPtr,char *buffer) { assert((*tokenPtr) != NULL); if ((*tokenPtr)->type==LPAREN) { (*tokenPtr)=nextToken((*tokenPtr),buffer,true); if ((*tokenPtr)==NULL) { printf("Syntax error... incomplete expression, expected an expression after open parens\n"); exit(1); } tree * result=getExpression(tokenPtr,buffer); if ((*tokenPtr)->type != RPAREN) { tokenError("Syntax error... expected closing parenthesis after expression",buffer,(*tokenPtr)); exit(1); } (*tokenPtr)=nextToken((*tokenPtr),buffer,true); return result; } if ((*tokenPtr)->type==INTEGER || (*tokenPtr)->type==VARIABLE ) { tree * result=newTree(); result->action=(*tokenPtr); (*tokenPtr)=nextToken((*tokenPtr),buffer,false); return result; } printf("Syntax error... expected a factor\n"); exit(1); }
int main(int argc,char **argv) { token * currentToken; char buffer[4096]; tree * t; bool debug=false; buffer[0]='\0'; if (argc < 2) { printf("Invoke as %s \"expression\"\n",argv[0]); return 1; } strcpy(buffer,argv[1]); currentToken=nextToken(NULL,buffer,false); t=getExpList(¤tToken,buffer); if (currentToken != NULL) { tokenError("Syntax error... data left after expression parsed",buffer,currentToken); buffer[currentToken->location]=0x00; } printf("%s = %ld\n",buffer,evalTree(t,debug)); freeTree(t); return 0; }
const char* RibLexerImpl::getString() { const RibToken& tok = m_tokenizer.get(); if(tok.type() != RibToken::STRING) tokenError("string", tok); std::string& storage = m_stringPool.getBuf(); storage.assign(tok.stringVal().begin(), tok.stringVal().end()); return storage.c_str(); }
float RibLexerImpl::getFloat() { const RibToken& tok = m_tokenizer.get(); switch(tok.type()) { case RibToken::INTEGER: return tok.intVal(); case RibToken::FLOAT: return tok.floatVal(); default: tokenError("float", tok); return 0; } }
const char* RibLexerImpl::nextRequest() { // Mark array pools as free to use. m_floatArrayPool.markUnused(); m_intArrayPool.markUnused(); m_stringArrayPool.markUnused(); m_stringPool.markUnused(); // Get the next token, and make sure it's a request token. const RibToken& tok = m_tokenizer.get(); if(tok.type() == RibToken::ENDOFFILE) return 0; else if(tok.type() != RibToken::REQUEST) tokenError("request", tok); std::string& storage = m_stringPool.getBuf(); // Using assign() rather than operator=() subverts the libstdc++ ref // counting for std::string, which is best avoided here since it seems to // result in extra churn on the heap. // // TODO: Replace the use of std::string with a minimal string buffer type // with explicit control over memory allocation. storage.assign(tok.stringVal().begin(), tok.stringVal().end()); return storage.c_str(); }
token * nextToken(token *current,char *buffer,bool delPrev) { token * result=newToken(); if (current!=NULL) { result->location=current->location+current->length; if (delPrev) freeToken(current); } while(result->length==0) { if (result->location >= strlen(buffer)) { free(result); return NULL; } switch(buffer[result->location]) { case ' ': case '\t': result->location=result->location+1; continue; case '+': result->type=PLUS; result->length=1; break; case '-': result->type=MINUS; result->length=1; break; case '*': result->type=MULTIPLY; result->length=1; break; case '/': result->type=DIVIDE; result->length=1; break; case ';' : result->type=EOS; result->length=1; break; case '(': result->type=LPAREN; result->length=1; break; case ')': result->type=RPAREN; result->length=1; break; case '{': result->type=LCURLY; result->length=1; break; case '}' : result->type=RCURLY; result->length=1; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': result->type=INTEGER; char *endptr; setValue(result,strtol(buffer+result->location,&endptr,10)); result->length=(endptr-buffer)-result->location; break; case 's': if (0==strncmp(buffer+result->location,"set",3)) { if ( (strlen(buffer)<=result->location+3) || (buffer[result->location+3]==' ') ) { result->type=SET; result->length=3; break; } } int ei=0; char varName[20]; while(isalpha((int)buffer[result->location+ei])) { varName[ei]=buffer[result->location+ei]; if (ei>=strlen(buffer)) break; ei++; varName[ei]='\0'; } result->type=VARIABLE; setName(result,varName); result->length=ei; break; case 'w': if (0==strncmp(buffer+result->location,"while",5)) { if ( (strlen(buffer)<=result->location+5) || (buffer[result->location+5]==' ') || (buffer[result->location+5]=='(') ) { result->type=WHILE; result->length=5; break; } } ei=0; while(isalpha((int)buffer[result->location+ei])) { varName[ei]=buffer[result->location+ei]; if (ei>=strlen(buffer)) break; ei++; varName[ei]='\0'; } result->type=VARIABLE; setName(result,varName); result->length=ei; break; default: if (isalpha((int)buffer[result->location])) { ei=0; while(isalpha((int)buffer[result->location+ei])) { varName[ei]=buffer[result->location+ei]; if (ei>=strlen(buffer)) break; ei++; varName[ei]='\0'; } result->type=VARIABLE; setName(result,varName); result->length=ei; break; } tokenError("Unrecognized token in expression",buffer,result); free(result); exit(1); } } return result; }