/* * Get the first "argument" in the given string, trimmed * and move source string pointer after the end of the argument. * For instance in string " foo, bar" this function will return "foo". * * This function returns NULL if no argument found * or a malloc'ed string that will have to be freed later. */ CompString FragmentParser::getFirstArgument (const CompString &line, size_t &pos) { CompString arg; CompString string; size_t next, temp, orig; int length; CompString retArg; if (pos >= line.size ()) return CompString (""); /* Left trim */ string = FragmentParser::ltrim (line.substr (pos)); orig = pos; pos = 0; /* Find next comma or semicolon (which isn't that useful since we * are working on tokens delimited by semicolons) */ if ((next = string.find (",", pos)) != std::string::npos || (next = string.find (";", pos)) != std::string::npos) { length = next - pos; if (!length) { pos = orig + 1; return getFirstArgument (line, pos); } if ((temp = string.find ("{", pos) != std::string::npos) && temp < next && (temp = string.find ("}", pos) != std::string::npos) && temp > next) { if ((next = string.find (",", temp)) != std::string::npos || (next = string.find (";", temp)) != std::string::npos) length = next - pos; else length = string.substr (pos).size (); } } else length = string.substr (pos).size (); /* Allocate, copy and end string */ arg = string.substr (pos, length); /* Increment source pointer */ if ((orig + arg.size () + 1) <= line.size ()) pos += orig + arg.size () + 1; else pos = std::string::npos; return arg; }
/* * Parse the source buffer op by op and add each op to function data * * FIXME : I am more than 200 lines long, I feel so heavy! */ void FragmentParser::programParseSource (GLFragment::FunctionData *data, int target, CompString &source) { CompString line, next; CompString current; CompString strtok; size_t pos = 0, strippos = 0; int length, oplength, type; CompString arg1, arg2, temp; /* Find the header, skip it, and start parsing from there */ pos = source.find ("!!ARBfp1.0", pos); if (pos != std::string::npos) { pos += 9; } /* Strip comments */ while ((strippos = source.find ("#", strippos)) != std::string::npos) { size_t carriagepos = source.find ("\n", strippos); if (carriagepos != std::string::npos) { source.erase (strippos, carriagepos - strippos); strippos = 0; } else source = source.substr (0, strippos); } strippos = 0; /* Strip linefeeds */ while ((strippos = source.find ("\n", strippos)) != std::string::npos) source[strippos] = ' '; /* Parse each instruction */ while (!(pos >= (source.size () - 1))) { size_t nPos = source.find (";", pos + 1); line = source.substr (pos + 1, nPos - pos); CompString origcurrent = current = ltrim (line); /* Find instruction type */ type = NoOp; /* Data ops */ if (current.substr (0, 3) == "END") type = NoOp; else if (current.substr (0, 3) == "ABS" || current.substr (0, 3) == "CMP" || current.substr (0, 3) == "COS" || current.substr (0, 3) == "DP3" || current.substr (0, 3) == "DP4" || current.substr (0, 3) == "EX2" || current.substr (0, 3) == "FLR" || current.substr (0, 3) == "FRC" || current.substr (0, 3) == "KIL" || current.substr (0, 3) == "LG2" || current.substr (0, 3) == "LIT" || current.substr (0, 3) == "LRP" || current.substr (0, 3) == "MAD" || current.substr (0, 3) == "MAX" || current.substr (0, 3) == "MIN" || current.substr (0, 3) == "POW" || current.substr (0, 3) == "RCP" || current.substr (0, 3) == "RSQ" || current.substr (0, 3) == "SCS" || current.substr (0, 3) == "SIN" || current.substr (0, 3) == "SGE" || current.substr (0, 3) == "SLT" || current.substr (0, 3) == "SUB" || current.substr (0, 3) == "SWZ" || current.substr (0, 3) == "TXP" || current.substr (0, 3) == "TXB" || current.substr (0, 3) == "XPD") type = DataOp; else if (current.substr (0, 4) == "TEMP") type = TempOp; else if (current.substr (0, 5) == "PARAM") type = ParamOp; else if (current.substr (0, 6) == "ATTRIB") type = AttribOp; else if (current.substr (0, 3) == "TEX") type = FetchOp; else if (current.substr (0, 3) == "ADD") { if (current.find ("fragment.texcoord", 0) != std::string::npos) programAddOffsetFromAddOp (current.c_str ()); else type = DataOp; } else if (current.substr (0, 3) == "MUL") { if (current.find ("fragment.color", 0) != std::string::npos) type = ColorOp; else type = DataOp; } else if (current.substr (0, 3) == "MOV") { if (current.find ("result.color", 0) != std::string::npos) type = ColorOp; else type = DataOp; } size_t cpos = 0; switch (type) { /* Data op : just copy paste the * whole instruction plus a ";" */ case DataOp: data->addDataOp (current.c_str ()); break; /* Parse arguments one by one */ case TempOp: case AttribOp: case ParamOp: { if (type == TempOp) oplength = 4; else if (type == ParamOp) oplength = 5; else if (type == AttribOp) oplength = 6; length = current.size (); if (length < oplength + 2) break; cpos = oplength + 1; while (current.size () && !(cpos >= current.size ()) && (arg1 = getFirstArgument (current, cpos)).size ()) { /* "output" is a reserved word, skip it */ if (arg1.substr (0, 6) == "output") continue; /* Add ops */ if (type == TempOp) data->addTempHeaderOp (arg1.c_str ()); else if (type == ParamOp) data->addParamHeaderOp (arg1.c_str ()); else if (type == AttribOp) data->addAttribHeaderOp (arg1.c_str ()); } } break; case FetchOp: { /* Example : TEX tmp, coord, texture[0], RECT; * "tmp" is dest name, while "coord" is either * fragment.texcoord[0] or an offset */ cpos += 3; if ((arg1 = getFirstArgument (current, cpos)).size ()) { if (!(temp = getFirstArgument (current, cpos)).size ()) break; if (temp == "fragment.texcoord[0]") data->addFetchOp (arg1.c_str (), NULL, target); else if (offsets.size ()) { arg2 = programFindOffset ( offsets.begin (), temp); if (arg2.size ()) data->addFetchOp (arg1.c_str (), arg2.c_str (), target); } } } break; case ColorOp: { if (current.substr (0, 3) == "MUL") /* MUL op, 2 ops */ { /* Example : MUL output, fragment.color, output; * MOV arg1, fragment.color, arg2 */ cpos += 3; if (!(arg1 = getFirstArgument (current, cpos)).size ()) { break; } if (!(temp = getFirstArgument (current, cpos)).size ()) break; if (!(arg2 = getFirstArgument (current, cpos)).size ()) break; data->addColorOp (arg1.c_str (), arg2.c_str ()); } else /* MOV op, 1 op */ { /* Example : MOV result.color, output; * MOV result.color, arg1; */ cpos = current.find (",") + 1; if ((arg1 = getFirstArgument (current, cpos)).size ()) data->addColorOp ("output", arg1.c_str ()); } break; } default: break; } pos = nPos; } programFreeOffset (); }