Subversion Repositories spk

Rev

Rev 1 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "bod_text_parser.h"
#include "../common/strutils.h"

#include <memory.h>
//---------------------------------------------------------------------------------
// ERROR
const char* bod_text_parser::Error::m_messages[]={
        "No error",
        "Newline in constant"
};

// TOKEN
const char* bod_text_parser::token::specialChars[]={ "{", "}", ";", ":", "=", "/!", "!/", "/#", "(", ")", "/", ".", "+" };
char bod_text_parser::token::tabWidth;

const char* bod_text_parser::token::getText() const
{ 
        if(type >= t_text)
                return text;
        else
                return specialChars[(int)type];
}
//---------------------------------------------------------------------------------
void bod_text_parser::preParseBuffer(char *pszBuffer, size_t size)
{
        m_pszBuffer=pszBuffer;
        m_buffLen=size;
}       
//---------------------------------------------------------------------------------
size_t bod_text_parser::parseBuffer(size_t limit)
{
        char *ln;
        size_t old=tokens.size();
        while(ln=nextLine()){
                if(parseLine(ln, ++m_lineIdx)==false)
                        break;
                        
                if(limit!=-1 && ((tokens.size() - old) >= limit)){
                        break;
                }
        }
        return tokens.size() - old;
}
//---------------------------------------------------------------------------------
#define PUSH_PREVIOUS_STRING() { t=new token(); \
t->type=token::t_text; \
t->line=idx; \
t->text=old; \
t->col=(int)(old - line + 1); \
tokens.push_back(t); }

#define PUSH_TOKEN(_type, _col, _text) { t=new token(); \
t->type=_type; \
t->line=idx; \
t->col=(int)(_col); \
t->text=_text; \
tokens.push_back(t); }

bool bod_text_parser::parseLine(char *line, int idx)
{
        char *old=line, *pos=line, ch;
        token *t;
        bool bInQuotedString=false;
        
        while(*pos!=0){
                ch=*pos;
                
                if(bInQuotedString || (ch=='"' && testFlag(parseQuotedStrings))){
                        if(ch=='"'){
                                bInQuotedString=!bInQuotedString;
                                
                                *pos=0;
                                if(bInQuotedString){
                                        if(*old!=0)
                                                PUSH_PREVIOUS_STRING();
                                }       
                                // got string
                                else
                                        PUSH_TOKEN(token::t_quotedString, old - line, old);
                                        
                                old=pos + 1;
                        }
                        else{
                                ++pos;
                                continue;
                        }
                }
                
                else if(ch==';' || ch==':' || (ch=='=' && testFlag(parseEqual)) || 
                (testFlag(parseOperators) && (ch=='.' || ch=='+'))) {
                        *pos=0;
                        
                        if(*old!=0)
                                PUSH_PREVIOUS_STRING();
                        
                        token::Type ty;
                        switch(ch){
                                case ';':
                                        ty=token::t_semicolon;
                                        break;
                                case ':':
                                        ty=token::t_colon;
                                        break;
                                case '=':
                                        ty=token::t_equal;
                                        break;
                                case '.':
                                        ty=token::t_dot;
                                        break;
                                case '+':
                                        ty=token::t_plus;
                                        break;
                        }
                        PUSH_TOKEN(ty, pos - line + 1, 0);
                        
                        old=pos + 1;
                }
                // space or tabulator
                else if(ch==' ' || ch==0x9){
                        *pos=0;
                        if(*old!=0)
                                PUSH_PREVIOUS_STRING();
                        
                        old=pos + 1;
                }
                // brackets
                else if(ch=='{' || ch=='}' || (testFlag(parseStdBrackets) && (ch=='(' || ch==')'))) {
                        *pos=0;
                        if(*old!=0)
                                PUSH_PREVIOUS_STRING();
                        
                        token::Type ty;
                        switch(ch){
                                case '{':
                                        ty=token::t_openCrBracket;
                                        break;
                                case '}':
                                        ty=token::t_closeCrBracket;
                                        break;
                                case '(':
                                        ty=token::t_openStdBracket;
                                        break;
                                case ')':
                                        ty=token::t_closeStdBracket;
                                        break;
                        }
                        PUSH_TOKEN(ty, pos - line + 1, 0);
                        
                        old=pos + 1;
                }
                // either comment, header info or processing instruction
                else if(ch=='/') {
                        if(pos[1]=='#'){
                                t=new token();
                                t->text=pos + 2;
                                while(*t->text!=0 && *t->text==' ')
                                        t->text++;
                                if(*t->text==0)
                                        delete t;
                                else{
                                        t->line=idx;
                                        t->col=(int)(pos - line) + 1;
                                        t->type=token::t_hdrinfo;
                                        tokens.push_back(t);
                                }
                        }
                        // open proc instruction /!
                        if(pos[1]=='!') {
                                PUSH_TOKEN(token::t_openInstrBlock, pos - line + 1, 0);
                                old=pos + 2;
                                pos++;
                        }
                        // slash
                        else{
                                /* if ignore slash is on then do nothing
                                  else treat it as comment unless C comments are specified, in which case there must
                                  be // to make comment, otherwise / is treated as token
                                */
                                if(testFlag(parseIgnoreSlash)==false){
                                        if(testFlag(parseBODComments)) {
                                                *pos=0;
                                                pos--;
                                        }
                                        else if(testFlag(parseCComments) && pos[1]=='/') {
                                                *pos=0;
                                                pos--;
                                        }
                                        else {
                                                *pos=0;
                                                if(*old!=0)
                                                        PUSH_PREVIOUS_STRING();
                                                
                                                PUSH_TOKEN(token::t_slash, pos - line + 1, 0);
                                                old=pos + 1;
                                        }
                                }
                        }
                }
                // close proc instruction !/
                else if(ch=='!' && pos[1]=='/'){
                        *pos=0;
                        if(*old!=0)
                                PUSH_PREVIOUS_STRING();
                        
                        PUSH_TOKEN(token::t_closeInstrBlock, pos - line + 1, 0);
                        old=pos + 2;
                        pos++;
                }
                
                pos++;
        }
        
        if(bInQuotedString){
                error(idx, (int)strlen(line), Error::errNewLineInConstant);
                return false;
        }
        // if there are some chars left after last delimeter (usually ;) this will process them
        if(old!=pos){
                PUSH_TOKEN(token::t_text, old - line + 1, old);
        }
        return true;
}
//---------------------------------------------------------------------------------
char * bod_text_parser::nextLine()
{
        size_t i, size=m_buffLen;
        char *line=0, *buffer=(char*)m_pszBuffer;
        
        for(i=m_lastPos; i < size; i++){
                if(buffer[i]==0xD){
                        buffer[i]=0;
                        m_newPos=i;
                        if(((i + 1) < size) && buffer[i+1]==0xA) {
                                m_newPos++;
                        }
                        m_newPos++;
                        line=buffer + m_lastPos;
                        
                        break;
                }
                else if(buffer[i]==0xA){
                        buffer[i]=0;
                        m_newPos=i + 1;
                        
                        line=buffer + m_lastPos;
                        break;
                }
        }
        if(m_lastPos > size) return NULL;
        
        if(line==0) {
                line=buffer + m_lastPos;
                m_newPos=size + 1;
        }
        
        m_lastPos=m_newPos;
        
        return line;
}
//---------------------------------------------------------------------------------