summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Merry <dev@randomguy3.me.uk>2013-03-22 22:26:12 +0000
committerAlex Merry <dev@randomguy3.me.uk>2013-03-22 22:54:32 +0000
commitdbd620bbaf7f28728c2686737b6a1453caaebd25 (patch)
tree8b2fd7257823983bb957ae7bc230080e9e32f7e7
parenta38c9405313dceae0f62c965fb99ae69b06b0548 (diff)
Rewrite the lexer to be context-aware
It turns out Flex can do modal lexing. This means that we can switch mode for optional properties, and also for co-ordinates. As a result, the parser is much simpler and doesn't keel over all the time on valid input.
-rw-r--r--tikzit/src/common/tikzlexer.lm104
-rw-r--r--tikzit/src/common/tikzparser.ym139
2 files changed, 116 insertions, 127 deletions
diff --git a/tikzit/src/common/tikzlexer.lm b/tikzit/src/common/tikzlexer.lm
index a9a2e51..3fd7b53 100644
--- a/tikzit/src/common/tikzlexer.lm
+++ b/tikzit/src/common/tikzlexer.lm
@@ -1,5 +1,10 @@
%option nounput
%option yylineno
+%s props
+%s xcoord
+%s ycoord
+%s noderef
+FLOAT \-?[0-9]*(\.[0-9]+)?
%{
//
@@ -7,6 +12,9 @@
// TikZiT
//
// Copyright 2010 Chris Heunen. All rights reserved.
+// Copyright 2012 Aleks Kissinger
+// Copyright 2012 KJ
+// Copyright 2013 Alex Merry
//
//
// This file is part of TikZiT.
@@ -45,48 +53,82 @@ extern int tokenpos;
tokenpos = 0;
yyless(1);
}
-[ ]+ { tokenpos += yyleng; } /* ignore whitespace */;
-[\t]+ { tokenpos += 4*yyleng; } /* ignore whitespace */;
-\\begin { tokenpos += yyleng; return LATEXBEGIN; }
-\\end { tokenpos += yyleng; return LATEXEND; }
-\{tikzpicture\} { tokenpos += yyleng; return TIKZPICTURE; }
-\{pgfonlayer\} { tokenpos += yyleng; return PGFONLAYER; }
-\( { tokenpos += yyleng; return LEFTPARENTHESIS; }
-\) { tokenpos += yyleng; return RIGHTPARENTHESIS; }
-\[ { tokenpos += yyleng; return LEFTBRACKET; }
-\] { tokenpos += yyleng; return RIGHTBRACKET; }
-; { tokenpos += yyleng; return SEMICOLON; }
-, { tokenpos += yyleng; return COMMA; }
-\. { tokenpos += yyleng; return FULLSTOP; }
-= { tokenpos += yyleng; return EQUALS; }
-\\draw { tokenpos += yyleng; return DRAW; }
-to { tokenpos += yyleng; return TO; }
-\\node { tokenpos += yyleng; return NODE; }
-\\path { tokenpos += yyleng; return PATH; }
-node { tokenpos += yyleng; return ALTNODE; }
+<INITIAL,xcoord,ycoord,props,noderef>[ ]+ { tokenpos += yyleng; } /* ignore whitespace */;
+<INITIAL,xcoord,ycoord,props,noderef>[\t]+ { tokenpos += 8*yyleng; } /* ignore whitespace */;
+\\begin\{tikzpicture\} { tokenpos += yyleng; return BEGIN_TIKZPICTURE_CMD; }
+\\end\{tikzpicture\} { tokenpos += yyleng; return END_TIKZPICTURE_CMD; }
+\\begin\{pgfonlayer\} { tokenpos += yyleng; return BEGIN_PGFONLAYER_CMD; }
+\\end\{pgfonlayer\} { tokenpos += yyleng; return END_PGFONLAYER_CMD; }
+\\draw { tokenpos += yyleng; return DRAW_CMD; }
+\\node { tokenpos += yyleng; return NODE_CMD; }
+\\path { tokenpos += yyleng; return PATH_CMD; }
rectangle { tokenpos += yyleng; return RECTANGLE; }
+node { tokenpos += yyleng; return NODE; }
at { tokenpos += yyleng; return AT; }
+to { tokenpos += yyleng; return TO; }
+; { tokenpos += yyleng; return SEMICOLON; }
-[0-9]+ {
- tokenpos += yyleng;
- yylval.nsstr=[NSString stringWithUTF8String:yytext];
- return NATURALNUMBER;
+\([ ]*{FLOAT}[ ]*,[ ]*{FLOAT}[ ]*\) {
+ tokenpos += 1;
+ yyless(1);
+ BEGIN(xcoord);
+}
+<xcoord>{FLOAT} {
+ tokenpos += yyleng;
+ yylval.pt.x=(float)strtod(yytext,NULL);
+ BEGIN(ycoord);
+}
+<ycoord>, { tokenpos += yyleng; }
+<ycoord>{FLOAT} {
+ tokenpos += yyleng;
+ yylval.pt.y=(float)strtod(yytext,NULL);
+}
+<ycoord>\) {
+ tokenpos += yyleng;
+ BEGIN(INITIAL);
+ return COORD;
}
-(\-?[0-9]*\.[0-9]+)|(\-?[0-9]+) {
- tokenpos += yyleng;
+ /* when we see "[", change parsing mode */
+\[ /*syntaxhlfix]*/ {
+ tokenpos += yyleng;
+ BEGIN(props);
+ return LEFTBRACKET;
+}
+<props>= { tokenpos += yyleng; return EQUALS; }
+<props>, { tokenpos += yyleng; return COMMA; }
+<props>[^=,\{\] \t]([^=,\{\]]*[^=,\{\] \t])? {
+ tokenpos += yyleng;
yylval.nsstr=[NSString stringWithUTF8String:yytext];
- return REALNUMBER;
+ return PROPSTRING;
+}
+<props>\] {
+ tokenpos += yyleng;
+ BEGIN(INITIAL);
+ return RIGHTBRACKET;
}
-\\?[a-zA-Z<>\-\'][a-zA-Z<>\-\'0-9]* { //'
- tokenpos += yyleng;
+\( {
+ tokenpos += yyleng;
+ BEGIN(noderef);
+ return LEFTPARENTHESIS;
+}
+<noderef>\. {
+ tokenpos += yyleng;
+ return FULLSTOP;
+}
+<noderef>[^\.\{\)]+ {
+ tokenpos += yyleng;
yylval.nsstr=[NSString stringWithUTF8String:yytext];
- return LWORD;
+ return REFSTRING;
+}
+<noderef>\) {
+ tokenpos += yyleng;
+ BEGIN(INITIAL);
+ return RIGHTPARENTHESIS;
}
-
-\{ {
+<INITIAL,props>\{ {
NSMutableString *buf = [NSMutableString string];
unsigned int brace_depth = 1;
unsigned int escape = 0;
diff --git a/tikzit/src/common/tikzparser.ym b/tikzit/src/common/tikzparser.ym
index 2277e23..170106f 100644
--- a/tikzit/src/common/tikzparser.ym
+++ b/tikzit/src/common/tikzparser.ym
@@ -44,55 +44,46 @@ extern void yyerror(const char *str);
%error-verbose
-%token LATEXBEGIN
-%token LATEXEND
-%token TIKZPICTURE
-%token PGFONLAYER
+%token BEGIN_TIKZPICTURE_CMD
+%token END_TIKZPICTURE_CMD
+%token BEGIN_PGFONLAYER_CMD
+%token END_PGFONLAYER_CMD
+%token DRAW_CMD
+%token NODE_CMD
+%token PATH_CMD
+%token RECTANGLE
+%token NODE
+%token AT
+%token TO
+%token SEMICOLON
+%token COMMA
+
%token LEFTPARENTHESIS
%token RIGHTPARENTHESIS
%token LEFTBRACKET
%token RIGHTBRACKET
-%token SEMICOLON
-%token COMMA
%token FULLSTOP
%token EQUALS
-%token DRAW
-%token TO
-%token NODE
-%token RECTANGLE
-%token PATH
-%token ALTNODE
-%token AT
-%token REALNUMBER
-%token NATURALNUMBER
-%token LWORD
+%token COORD
+%token PROPSTRING
+%token REFSTRING
%token DELIMITEDSTRING
%type<nsstr> nodename
-%type<nsstr> anchor
-%type<nsstr> anchorsym
%type<nsstr> optanchor
-%type<nsstr> nodeid
-%type<pt> coords
-%type<nsstr> propsym
-%type<nsstr> propsyms
%type<nsstr> val
-%type<nsstr> number
%%
-tikzpicture: LATEXBEGIN TIKZPICTURE optproperties expressions LATEXEND TIKZPICTURE;
-expressions: expressions expression | ;
-expression: node | edge | boundingbox | ignore;
-
-ignore: LATEXBEGIN PGFONLAYER DELIMITEDSTRING | LATEXEND PGFONLAYER;
+tikzpicture: BEGIN_TIKZPICTURE_CMD optproperties tikzcmds END_TIKZPICTURE_CMD;
+tikzcmds: tikzcmds tikzcmd | ;
+tikzcmd: node | edge | boundingbox | ignore;
-number: REALNUMBER { $$ = $<nsstr>1; } | NATURALNUMBER { $$ = $<nsstr>1; };
+ignore: BEGIN_PGFONLAYER_CMD DELIMITEDSTRING | END_PGFONLAYER_CMD;
optproperties: LEFTBRACKET properties RIGHTBRACKET | ;
properties: property extraproperties;
-extraproperties: COMMA property extraproperties | property extraproperties | ;
-
+extraproperties: COMMA property extraproperties | ;
property:
val EQUALS val
{
@@ -108,79 +99,33 @@ property:
[[a data] addObject:p];
[p release];
};
+val: PROPSTRING { $$ = $<nsstr>1; } | DELIMITEDSTRING { $$ = $<nsstr>1; };
-val: propsyms { $$ = $<nsstr>1; } | DELIMITEDSTRING { $$ = $<nsstr>1; };
-propsyms:
- propsym { $$ = $<nsstr>1; }
- | propsyms propsym
- {
- NSString *s = [$<nsstr>1 stringByAppendingFormat:@" %@", $<nsstr>2];
- $$ = s;
- };
-
-propsym:
- LWORD { $$ = $<nsstr>1; }
- | number { $$ = $<nsstr>1; }
- | TO { $$ = @"to"; }
- | ALTNODE { $$ = @"node"; }
- | RECTANGLE { $$ = @"rectangle"; }
- | AT { $$ = @"at"; }
- | FULLSTOP { $$ = @"."; };
-
-
-nodecmd : NODE { [[TikzGraphAssembler currentAssembler] prepareNode]; };
-
-nodename: LEFTPARENTHESIS nodeid RIGHTPARENTHESIS { $$ = $<nsstr>2; };
-
-node:
- nodecmd optproperties nodename AT coords nodelabel SEMICOLON
+nodecmd: NODE_CMD { [[TikzGraphAssembler currentAssembler] prepareNode]; };
+nodename: LEFTPARENTHESIS REFSTRING RIGHTPARENTHESIS { $$ = $<nsstr>2; };
+node: nodecmd optproperties nodename AT COORD DELIMITEDSTRING SEMICOLON
{
TikzGraphAssembler *a = [TikzGraphAssembler currentAssembler];
[[a currentNode] setName:$<nsstr>3];
[[a currentNode] setPoint:$<pt>5];
+ [[a currentNode] setLabel:$<nsstr>6];
[a finishNode];
};
-nodelabel:
- DELIMITEDSTRING
+edgecmd : DRAW_CMD { [[TikzGraphAssembler currentAssembler] prepareEdge]; };
+edge: edgecmd optproperties source TO optedgenode target SEMICOLON
{
- Node *n = [[TikzGraphAssembler currentAssembler] currentNode];
- [n setLabel:$<nsstr>1];
- }
-
-anchor: anchorsym { $$ = $<nsstr>1; }
- | anchor anchorsym
- {
- NSString *s = [$<nsstr>1 stringByAppendingFormat:@" %@", $<nsstr>2];
- $$ = s;
+ TikzGraphAssembler *a = [TikzGraphAssembler currentAssembler];
+ [a finishEdge];
};
-anchorsym: LWORD { $$ = $<nsstr>1; } | NATURALNUMBER { $$ = $<nsstr>1; };
-
-optanchor: { $$ = @""; } | FULLSTOP anchor { $$ = $<nsstr>2; };
-
-source: LEFTPARENTHESIS nodeid optanchor RIGHTPARENTHESIS
+optanchor: { $$ = @""; } | FULLSTOP REFSTRING { $$ = $<nsstr>2; };
+source: LEFTPARENTHESIS REFSTRING optanchor RIGHTPARENTHESIS
{
TikzGraphAssembler *a = [TikzGraphAssembler currentAssembler];
[a setEdgeSource:$<nsstr>2
anchor:$<nsstr>3];
};
-
-nodeid: LWORD { $$ = $<nsstr>1; } | NATURALNUMBER { $$ = $<nsstr>1; };
-
-coords:
- LEFTPARENTHESIS number COMMA number RIGHTPARENTHESIS
- {
- $$ = NSMakePoint([$<nsstr>2 floatValue], [$<nsstr>4 floatValue]);
- };
-
-edgecmd : DRAW { [[TikzGraphAssembler currentAssembler] prepareEdge]; };
-edge:
- edgecmd optproperties source TO optedgenode target SEMICOLON
- {
- TikzGraphAssembler *a = [TikzGraphAssembler currentAssembler];
- [a finishEdge];
- };
-target: LEFTPARENTHESIS nodeid optanchor RIGHTPARENTHESIS
+target: LEFTPARENTHESIS REFSTRING optanchor RIGHTPARENTHESIS
{
TikzGraphAssembler *a = [TikzGraphAssembler currentAssembler];
[a setEdgeTarget:$<nsstr>2
@@ -194,18 +139,20 @@ target: LEFTPARENTHESIS nodeid optanchor RIGHTPARENTHESIS
};
selfloop: LEFTPARENTHESIS RIGHTPARENTHESIS;
-altnodecmd: ALTNODE { [[TikzGraphAssembler currentAssembler] prepareNode]; };
+edgenodecmd: NODE { [[TikzGraphAssembler currentAssembler] prepareNode]; };
optedgenode:
- | altnodecmd optproperties nodelabel
+ | edgenodecmd optproperties DELIMITEDSTRING
{
- [[TikzGraphAssembler currentAssembler] finishNode];
+ TikzGraphAssembler *a = [TikzGraphAssembler currentAssembler];
+ [[a currentNode] setLabel:$<nsstr>3];
+ [a finishNode];
}
-bbox_ignoreprops:
- | LEFTBRACKET LWORD LWORD LWORD LWORD RIGHTBRACKET;
-
+ignoreprop: val | val EQUALS val;
+ignoreprops: ignoreprop ignoreprops | ;
+optignoreprops: LEFTBRACKET ignoreprops RIGHTBRACKET;
boundingbox:
- PATH bbox_ignoreprops coords RECTANGLE coords SEMICOLON
+ PATH_CMD optignoreprops COORD RECTANGLE COORD SEMICOLON
{
Graph *g = [[TikzGraphAssembler currentAssembler] graph];
[g setBoundingBox:NSRectAroundPoints($<pt>3, $<pt>5)];