From a8a8dfb90d6a51ae369c042c95162f45754c7c4b Mon Sep 17 00:00:00 2001 From: randomguy3 Date: Mon, 9 Jan 2012 11:00:50 +0000 Subject: Move tikzit into "trunk" directory git-svn-id: https://tikzit.svn.sourceforge.net/svnroot/tikzit/trunk@365 7c02a99a-9b00-45e3-bf44-6f3dd7fddb64 --- tikzit/src/osx/TikzParser.m | 574 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 574 insertions(+) create mode 100644 tikzit/src/osx/TikzParser.m (limited to 'tikzit/src/osx/TikzParser.m') diff --git a/tikzit/src/osx/TikzParser.m b/tikzit/src/osx/TikzParser.m new file mode 100644 index 0000000..2bb5a15 --- /dev/null +++ b/tikzit/src/osx/TikzParser.m @@ -0,0 +1,574 @@ +// +// TikzParser.m +// TikZiT +// +// Copyright 2010 Aleks Kissinger. All rights reserved. +// +// +// This file is part of TikZiT. +// +// TikZiT is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// TikZiT is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with TikZiT. If not, see . +// + +#import "TikzParser.h" + +// custom parsekit extensions +#import "PKNaturalNumber.h" +#import "PKRepetition+RepeatPlus.h" +#import "PKSpecificDelimitedString.h" +#import "PKBalancingDelimitState.h" + +#import "util.h" + +@interface TikzParser () + +- (NSString*)popAllToString:(PKAssembly*)a withSeparator:(NSString*)sep; +- (PKParser*)eatSymbol:(NSString*)s; +- (PKParser*)eatLiteral:(NSString*)s; +- (PKParser*)eatWord; + +// properties +- (void)willMatchProplist:(PKAssembly*)a; +- (void)didMatchProplist:(PKAssembly*)a; +- (void)willMatchProperty:(PKAssembly*)a; +- (void)didMatchArrowSpecDash:(PKAssembly*)a; + +// nodes +- (void)didMatchNodeCommand:(PKAssembly*)a; +- (void)didMatchNodeLabel:(PKAssembly*)a; +- (void)didMatchNode:(PKAssembly*)a; +- (void)didMatchNodeName:(PKAssembly*)a; +- (void)didMatchCoords:(PKAssembly*)a; + +// edges +- (void)didMatchDrawCommand:(PKAssembly *)a; +- (void)didMatchEdge:(PKAssembly*)a; +- (void)didMatchEdgeNodeCommand:(PKAssembly*)a; +- (void)didMatchEdgeNode:(PKAssembly*)a; + +// bounding box +- (void)didMatchPathCommand:(PKAssembly*)a; +- (void)didMatchBoundingBox:(PKAssembly*)a; + +// tikzpicture +- (void)willMatchTikzPicture:(PKAssembly*)a; +- (void)didMatchTikzPicture:(PKAssembly*)a; + +@end + + +@implementation TikzParser + +@synthesize graph; + +- (id)init { + [super init]; + + currentKey = nil; + currentSourceArrow = nil; + tokenizer = [PKTokenizer tokenizer]; + + graph = nil; + currentNode = nil; + currentEdge = nil; + matchingEdgeNode = NO; + + // tweak the tokenizer a bit + [tokenizer.symbolState remove:@"<="]; + [tokenizer.symbolState remove:@">="]; + [tokenizer.symbolState remove:@"{"]; + [tokenizer.symbolState remove:@"}"]; + [tokenizer setTokenizerState:tokenizer.wordState from:'\\' to:'\\']; + [tokenizer.wordState setWordChars:NO from:'-' to:'-']; + tokenizer.delimitState = [[PKBalancingDelimitState alloc] init]; + [tokenizer.delimitState addStartMarker:@"{" + endMarker:@"}" + allowedCharacterSet:nil]; + [tokenizer setTokenizerState:tokenizer.delimitState from:'{' to:'{']; + + /* + + + GRAMMAR FOR TIKZPICTURE + + tikzpicture = '\begin' '{tikzpicture}' + optproplist + expr* + '\end' '{tikzpicture}' + expr = node | edge | boundingbox | layerexpr + layerexpr = '\begin' '{pgfonlayer}' DelimitedString | '\end' '{pgfonlayer}' + + + GRAMMAR FOR PROPERTY LISTS + + optproplist = proplist | Empty; + proplist = '[' property property1* ']'; + property = arrowspec | keyval | atom; + property1 = ',' property; + keyval = key '=' val; + atom = propsym+; + arrowspec = propsym* '-' propsym*; + key = propsym+; + val = propsym+ | QuotedString; + propsym = (Word | Number | '<' | '>'); + + + GRAMMAR FOR NODES + + node = '\node' optproplist name 'at' coords DelimitedString ';'; + nodename = '(' nodeid ')'; + nodeid = Word | NaturalNumber; + coords = '(' Number ',' Number ')'; + + + GRAMMAR FOR EDGES + + edge = '\draw' optproplist nodename 'to' optedgenode ( nodename | selfloop ) ';'; + selfloop = '(' ')'; + optedgenode = Empty | edgenode + edgenode = 'node' optproplist name coords '{' '}' ';'; + + GRAMMAR FOR BOUNDING BOX + + boundingbox = '\path' '[' 'use' 'as' 'bounding' 'box' ']' coords 'rectangle' coords ';' + + */ + + + PKAlternation *nodeid = [PKAlternation alternation]; + nodeid.name = @"node identifier"; + [nodeid add:[PKWord word]]; + [nodeid add:[PKNaturalNumber number]]; + + PKAlternation *propsym = [PKAlternation alternation]; + propsym.name = @"property symbol"; + [propsym add:[PKWord word]]; + [propsym add:[PKNumber number]]; + [propsym add:[PKSymbol symbolWithString:@"<"]]; + [propsym add:[PKSymbol symbolWithString:@">"]]; + + PKSequence *anchor = [PKSequence sequence]; + [anchor add:[self eatSymbol:@"."]]; + [anchor add:[self eatWord]]; + + PKAlternation *optanchor = [PKAlternation alternation]; + [optanchor add:anchor]; + [optanchor add:[PKEmpty empty]]; + + PKSequence *nodename = [PKSequence sequence]; + nodename.name = @"node name"; + [nodename add:[self eatSymbol:@"("]]; + [nodename add:nodeid]; + [nodename add:optanchor]; + [nodename add:[self eatSymbol:@")"]]; + [nodename setAssembler:self selector:@selector(didMatchNodeName:)]; + + PKTrack *coords = [PKTrack track]; + coords.name = @"coordinate definition"; + [coords add:[self eatSymbol:@"("]]; + [coords add:[PKNumber number]]; + [coords add:[self eatSymbol:@","]]; + [coords add:[PKNumber number]]; + [coords add:[self eatSymbol:@")"]]; + [coords setAssembler:self selector:@selector(didMatchCoords:)]; + + PKSequence *key = [PKRepetition repetitionPlusWithSubparser:propsym]; + + PKAlternation *val = [PKAlternation alternation]; + [val add:[PKRepetition repetitionPlusWithSubparser:propsym]]; + [val add:[PKQuotedString quotedString]]; + [val setPreassembler:self selector:@selector(willMatchVal:)]; + + PKSequence *keyval = [PKSequence sequence]; + [keyval add:key]; + [keyval add:[self eatLiteral:@"="]]; + [keyval add:val]; + + PKSequence *atom = [PKRepetition repetitionPlusWithSubparser:propsym]; + + PKSymbol *arrowspecdash = [PKSymbol symbolWithString:@"-"]; + [arrowspecdash setAssembler:self selector:@selector(didMatchArrowSpecDash:)]; + + PKSequence *arrowspec = [PKSequence sequence]; + [arrowspec add:[PKRepetition repetitionWithSubparser:propsym]]; + [arrowspec add:arrowspecdash]; + [arrowspec add:[PKRepetition repetitionWithSubparser:propsym]]; + + PKAlternation *property = [PKAlternation alternation]; + property.name = @"property, atom, or arrow specification"; + [property add:keyval]; + [property add:arrowspec]; + [property add:atom]; + [property setPreassembler:self selector:@selector(willMatchProperty:)]; + + PKSequence *property1 = [PKSequence sequence]; + [property1 add:[self eatLiteral:@","]]; + [property1 add:property]; + + PKTrack *proplist = [PKTrack track]; + proplist.name = @"property list"; + [proplist add:[self eatSymbol:@"["]]; + [proplist add:property]; + [proplist add:[PKRepetition repetitionWithSubparser:property1]]; + [proplist add:[self eatSymbol:@"]"]]; + [proplist setPreassembler:self selector:@selector(willMatchProplist:)]; + [proplist setAssembler:self selector:@selector(didMatchProplist:)]; + + PKAlternation *optproplist = [PKAlternation alternation]; + [optproplist add:proplist]; + [optproplist add:[PKEmpty empty]]; + + PKLiteral *nodeCommand = [PKLiteral literalWithString:@"\\node"]; + [nodeCommand setAssembler:self selector:@selector(didMatchNodeCommand:)]; + + PKTerminal *nodeLabel = [PKDelimitedString delimitedString]; + nodeLabel.name = @"Possibly empty node label"; + [nodeLabel setAssembler:self selector:@selector(didMatchNodeLabel:)]; + + PKTrack *node = [PKTrack track]; + [node add:nodeCommand]; + [node add:optproplist]; + [node add:nodename]; + [node add:[self eatLiteral:@"at"]]; + [node add:coords]; + [node add:nodeLabel]; + //[node add:[[PKDelimitedString delimitedString] discard]]; + [node add:[self eatSymbol:@";"]]; + [node setAssembler:self selector:@selector(didMatchNode:)]; + + PKLiteral *drawCommand = [PKLiteral literalWithString:@"\\draw"]; + [drawCommand setAssembler:self selector:@selector(didMatchDrawCommand:)]; + + PKSequence *parens = [PKSequence sequence]; + [parens add:[self eatSymbol:@"("]]; + [parens add:[self eatSymbol:@")"]]; + + PKAlternation *nodenamealt = [PKAlternation alternation]; + nodenamealt.name = @"node name or '()'"; + [nodenamealt add:nodename]; + [nodenamealt add:parens]; + + PKLiteral *edgenodeCommand = [PKLiteral literalWithString:@"node"]; + edgenodeCommand.name = @"edge node command"; + [edgenodeCommand setAssembler:self selector:@selector(didMatchEdgeNodeCommand:)]; + + PKSequence *edgenode = [PKSequence sequence]; + [edgenode add:edgenodeCommand]; + [edgenode add:optproplist]; + [edgenode add:nodeLabel]; + edgenode.name = @"edge node"; + [edgenode setAssembler:self selector:@selector(didMatchEdgeNode:)]; + + + PKAlternation *optedgenode = [PKAlternation alternation]; + [optedgenode add:[PKEmpty empty]]; + [optedgenode add:edgenode]; + + + PKTrack *edge = [PKTrack track]; + [edge add:drawCommand]; + [edge add:optproplist]; + [edge add:nodename]; + [edge add:[self eatLiteral:@"to"]]; + [edge add:optedgenode]; + [edge add:nodenamealt]; + [edge add:[self eatSymbol:@";"]]; + [edge setAssembler:self selector:@selector(didMatchEdge:)]; + + + PKLiteral *pathliteral = [PKLiteral literalWithString:@"\\path"]; + [pathliteral setAssembler:self selector:@selector(didMatchPathCommand:)]; + + PKTrack *boundingbox = [PKTrack track]; + [boundingbox add:pathliteral]; + [boundingbox add:[self eatSymbol:@"["]]; + [boundingbox add:[self eatLiteral:@"use"]]; + [boundingbox add:[self eatLiteral:@"as"]]; + [boundingbox add:[self eatLiteral:@"bounding"]]; + [boundingbox add:[self eatLiteral:@"box"]]; + [boundingbox add:[self eatSymbol:@"]"]]; + [boundingbox add:coords]; + [boundingbox add:[self eatLiteral:@"rectangle"]]; + [boundingbox add:coords]; + [boundingbox add:[self eatSymbol:@";"]]; + [boundingbox setAssembler:self selector:@selector(didMatchBoundingBox:)]; + + PKTerminal *layerLiteral = + [[PKSpecificDelimitedString delimitedStringWithValue:@"{pgfonlayer}"] + discard]; + + PKSequence *beginLayer = [PKSequence sequence]; + [beginLayer add:[self eatLiteral:@"\\begin"]]; + [beginLayer add:layerLiteral]; + [beginLayer add:[[PKDelimitedString delimitedString] discard]]; + + PKSequence *endLayer = [PKSequence sequence]; + [endLayer add:[self eatLiteral:@"\\end"]]; + [endLayer add:layerLiteral]; + + PKAlternation *expr = [PKAlternation alternation]; + [expr add:node]; + [expr add:edge]; + [expr add:boundingbox]; + [expr add:beginLayer]; + [expr add:endLayer]; + + PKTerminal *tikzpicLiteral = + [[PKSpecificDelimitedString delimitedStringWithValue:@"{tikzpicture}"] + discard]; + + //tikzpicLiteral.name = @"{tikzpicture}"; + + PKTrack *tikzpic = [PKTrack track]; + [tikzpic add:[PKEmpty empty]]; + [tikzpic add:[self eatLiteral:@"\\begin"]]; + [tikzpic add:tikzpicLiteral]; + [tikzpic add:optproplist]; + [tikzpic add:[PKRepetition repetitionWithSubparser:expr]]; + [tikzpic add:[self eatLiteral:@"\\end"]]; + [tikzpic add:tikzpicLiteral]; + [tikzpic setPreassembler:self selector:@selector(willMatchTikzPicture:)]; + [tikzpic setAssembler:self selector:@selector(didMatchTikzPicture:)]; + + nodeParser = node; + edgeParser = edge; + tikzPictureParser = tikzpic; + + return self; +} + +- (NSString*)popAllToString:(PKAssembly*)a withSeparator:(NSString*)sep { + NSString *str = @""; + BOOL fst = YES; + + while (![a isStackEmpty]) { + if (fst) fst = NO; + else str = [sep stringByAppendingString:str]; + + PKToken *tok = [a pop]; + str = [tok.stringValue stringByAppendingString:str]; + } + + return str; +} + +- (PKParser*)eatSymbol:(NSString*)s { + return [[PKSymbol symbolWithString:s] discard]; +} + +- (PKParser*)eatLiteral:(NSString*)s { + return [[PKLiteral literalWithString:s] discard]; +} + +- (PKParser*)eatWord { + return [[PKWord word] discard]; +} + +- (void)packProperty:(PKAssembly*)a { + BOOL empty = [a isStackEmpty]; + NSString *val = [self popAllToString:a withSeparator:@" "]; + + if (currentKey != nil) { + [elementData setProperty:val forKey:currentKey]; +// NSLog(@" keyval: (%@) => (%@)", currentKey, val); + } else if (currentSourceArrow != nil) { + [elementData setArrowSpecFrom:currentSourceArrow to:val]; +// NSLog(@" arrowspec: (%@-%@)", currentSourceArrow, val); + } else if (!empty) { + [elementData setAtom:val]; +// NSLog(@" atom: (%@)", val); + } + + currentKey = nil; + currentSourceArrow = nil; +} + +- (BOOL)parseNode:(NSString *)str { + tokenizer.string = str; + PKAssembly *res = [nodeParser completeMatchFor:[PKTokenAssembly assemblyWithTokenizer:tokenizer]]; + +// NSLog(@"result: %@", res); + return res != nil; +} + +- (BOOL)parseEdge:(NSString *)str { + tokenizer.string = str; + PKAssembly *res = [edgeParser completeMatchFor:[PKTokenAssembly assemblyWithTokenizer:tokenizer]]; + +// NSLog(@"result: %@", res); + return res != nil; +} + +- (BOOL)parseTikzPicture:(NSString*)str forGraph:(Graph*)g { + self.graph = g; + tokenizer.string = str; + PKTokenAssembly *assm = [PKTokenAssembly assemblyWithTokenizer:tokenizer]; + PKAssembly *res = [tikzPictureParser completeMatchFor:assm]; + +// NSLog(@"result: %@", res); + return res != nil; +} + +- (BOOL)parseTikzPicture:(NSString *)str { + return [self parseTikzPicture:str forGraph:[Graph graph]]; +} + + +- (void)didMatchNodeCommand:(PKAssembly*)a { + [a pop]; + currentNode = [Node node]; + [currentNode updateData]; +// NSLog(@""); +} + +- (void)didMatchNodeLabel:(PKAssembly*)a { + PKToken *tok = [a pop]; + NSString *s = tok.stringValue; + s = [s substringWithRange:NSMakeRange(1, [s length]-2)]; + if (matchingEdgeNode) currentEdge.edgeNode.label = s; + else currentNode.label = s; +} + +- (void)didMatchNode:(PKAssembly*)a { + [nodeTable setObject:currentNode forKey:currentNode.name]; + [graph addNode:currentNode]; + currentNode = nil; +// NSLog(@""); +} + +- (void)didMatchDrawCommand:(PKAssembly*)a { + [a pop]; + currentEdge = [Edge edge]; + sourceName = nil; + targName = nil; +// NSLog(@""); +} + +- (void)didMatchEdge:(PKAssembly*)a { + Node *src = [nodeTable objectForKey:sourceName]; + currentEdge.source = src; + currentEdge.target = (targName == nil) ? src : [nodeTable objectForKey:targName]; + [currentEdge setAttributesFromData]; + [graph addEdge:currentEdge]; + currentEdge = nil; +// NSLog(@""); +} + +- (void)didMatchEdgeNodeCommand:(PKAssembly*)a { + [a pop]; + matchingEdgeNode = YES; + currentEdge.edgeNode = [Node node]; +} + +- (void)didMatchEdgeNode:(PKAssembly*)a { + matchingEdgeNode = NO; +} + +- (void)willMatchVal:(PKAssembly*)a { + currentKey = [self popAllToString:a withSeparator:@" "]; +// NSLog(@"key: %@", currentKey); +} + +- (void)willMatchProperty:(PKAssembly*)a { + [self packProperty:a]; +} + +- (void)willMatchProplist:(PKAssembly*)a { + elementData = [[GraphElementData alloc] init]; +} + +- (void)didMatchProplist:(PKAssembly*)a { + [self packProperty:a]; + + if (currentNode != nil) { + currentNode.data = elementData; + } else if (currentEdge != nil) { + if (matchingEdgeNode) currentEdge.edgeNode.data = elementData; + else currentEdge.data = elementData; + } else { // add properties to to graph + graph.data = elementData; + } + + elementData = nil; +} + +- (void)didMatchNodeName:(PKAssembly*)a { + NSString *name = ((PKToken*)[a pop]).stringValue; + + if (currentNode != nil) { + currentNode.name = name; +// NSLog(@" name: (%@)", name); + } else if (currentEdge != nil) { + if (sourceName == nil) { + sourceName = name; +// NSLog(@" source: (%@)", name); + } else { + targName = name; +// NSLog(@" target: (%@)", name); + } + } +} + +- (void)didMatchCoords:(PKAssembly*)a { + NSPoint p; + p.y = ((PKToken*)[a pop]).floatValue; + p.x = ((PKToken*)[a pop]).floatValue; + + if (currentNode != nil) { + currentNode.point = p; + } else { + if (bboxFirstPoint) { + bboxFirstPoint = NO; + bbox1 = p; + } else { + bbox2 = p; + } + } + +// NSLog(@" coord: (%f, %f)", p.x, p.y); +} + +- (void)didMatchPathCommand:(PKAssembly*)a { + [a pop]; + bboxFirstPoint = YES; +} + +- (void)didMatchBoundingBox:(PKAssembly*)a { + graph.boundingBox = NSRectAroundPoints(bbox1, bbox2); +} + +- (void)didMatchArrowSpecDash:(PKAssembly*)a { + [a pop]; // pop off the dash + currentSourceArrow = [self popAllToString:a withSeparator:@" "]; +} + +- (void)willMatchTikzPicture:(PKAssembly*)a { +// NSLog(@""); + nodeTable = [NSMutableDictionary dictionary]; +} + +- (void)didMatchTikzPicture:(PKAssembly*)a { +// NSLog(@""); +// NSLog(@"%@", [graph tikz]); +} + +- (void)finalize { +// NSLog(@"releasing subparser trees"); + PKReleaseSubparserTree(nodeParser); + PKReleaseSubparserTree(edgeParser); + PKReleaseSubparserTree(tikzPictureParser); + [super finalize]; +} + +@end -- cgit v1.2.3