Reputation: 9
I'm trying to make a simple drawing program that reads in translate (rect 10 10 10 10) 50 50
. What I'm trying to do is split it so that the 50 50
goes with the translate
and the rect
keeps all the 10
s.
This is a PostScript fill. I've heard of hash tables and stacks, but I'm not sure how to use them. I've done everything else (e.x. all the calculations for the shapes). I just don't understand how to parse the lines so that I can get the numbers pointing to the right variables.
Upvotes: 0
Views: 763
Reputation: 5538
Here is how you can write this C++ parser using AXE library:
Rect r;
auto rect = "(rect "
& r_decimal(r.left) & space
& r_decimal(r.top) & space
& r_decimal(r.right) & space
& r_decimal(r.bottom) & space
& ')';
Point t;
auto translate = "translate " & rect
& space & r_decimal(t.x)
& space & r_decimal(t.y);
// test it
std::string str("translate (rect 10 10 10 10) 50 50");
auto match = translate(str.begin(), str.end());
That will parse a single translate statement in PS file. If you need to parse all translate statements and don't care to write a full blown parser for postscript format, you can use *r_find(translate)
rule to skip input that you don't care about. r_find(R)
rule searches the input until the rule R
is found. Now that's pretty easy and it will also generate very fast code, probably faster than hand-written with "if"-s and "else"-s.
Disclaimer: I din't test the code above, so minor errors are possible.
Upvotes: 0
Reputation: 40669
Well, this might be a little old-fashioned, but it's simple and there's nothing faster.
void scanWhite(char*& p){
while(*p==' ') p++;
}
bool seeInt(char*& p, int& num){
scanWhite(p);
char* p1 = p;
bool bNegative = false;
if (*p=='-'){bNegative = true; p++;)
if (!isdigit(*p){p = p1; return false;}
num = 0;
while(isdigit(*p)){
num *= 10;
num += (*p - '0');
p++;
}
if (bNegative) num = - num;
return true;
}
bool seeWord(char*& p, char* word){
scanWhite(p);
int len = strlen(word);
if (strncmp(p, word, len)==0 && !isalphanumeric(p[len])){
p += len;
return true;
}
else return false;
}
bool seeChar(char*& p, char c){
scanWhite(p);
if (*p != c) return false;
p++;
return true;
}
bool parseTranslateRect(char*& p
, int& x0, int& y0, int& x1, int& y1
, int& dx, int& dy
)
{
if (!seeChar(p, '(')) return false;
if (!seeWord(p, "translate")) return false;
if (!seeChar(p, '(')) return false;
if (!seeWord(p, "rect")) return false;
if (!seeInt(p, &x0)) return false;
if (!seeInt(p, &y0)) return false;
if (!seeInt(p, &x1)) return false;
if (!seeInt(p, &y1)) return false;
if (!seeChar(p, ')')) return false;
if (!seeInt(p, &dx)) return false;
if (!seeInt(p, &dy)) return false;
if (!seeChar(p, ')')) return false;
return true;
}
If you've got many copies of "(translate (rect ...", just call the parse routine over and over until it returns false.
Upvotes: 0
Reputation: 71525
Your example looks like a Lisp s-expression, so try searching for "s-expression parser". A few hits come up.
If you want to go "whole hog", you could implement your shape routines as C++ classes, use SWIG to expose them to GNU Guile, and write your application in Scheme. That is probably not what you had in mind, though. :-)
Upvotes: 1