From 8cde489ab6c4169fb03d810447c18eea0d0eaa14 Mon Sep 17 00:00:00 2001 From: Alex Merry Date: Sat, 23 Mar 2013 03:30:19 +0000 Subject: Make the parser/lexer reentrant No more locking! Also, the interface for TikzGraphAssembler is much simpler. Changes to OSX code are completely untested. --- tikzit/src/common/TikzGraphAssembler.m | 243 ++++++++++++++++++--------------- 1 file changed, 133 insertions(+), 110 deletions(-) (limited to 'tikzit/src/common/TikzGraphAssembler.m') diff --git a/tikzit/src/common/TikzGraphAssembler.m b/tikzit/src/common/TikzGraphAssembler.m index 26bf515..5a01036 100644 --- a/tikzit/src/common/TikzGraphAssembler.m +++ b/tikzit/src/common/TikzGraphAssembler.m @@ -22,84 +22,72 @@ // #import "TikzGraphAssembler.h" +#import "TikzGraphAssembler+Parser.h" +#import "tikzparser.h" +#import "tikzlexer.h" #import "NSError+Tikzit.h" -extern int yyparse(void); -extern int yylex(void); -extern int yy_scan_string(const char* yy_str); -extern void yy_delete_buffer(int b); -extern int yylex_destroy(void); - - -static NSLock *parseLock = nil; -static id currentAssembler = nil; - -extern int yylineno; -extern int yyleng; -int lineno; -int tokenpos; -extern char *yystr; -char linebuff[500]; - - -void yyerror(const char *str) { - // if the error is on the first line, treat specially - if(lineno == 1){ -// strcpy(linebuff, yytext+1); - NSLog(@"Problem ahoy!"); - } - - NSLog(@"Parse error on line %i: %s\n%s\n%@\n", lineno, str, linebuff, [[@"" stringByPaddingToLength:(tokenpos-yyleng) withString: @" " startingAtIndex:0] stringByAppendingString:[@"" stringByPaddingToLength:yyleng withString: @"^" startingAtIndex:0]]); - if (currentAssembler != nil) { - NSError *error = [NSError errorWithDomain:@"net.sourceforge.tikzit" - code:TZ_ERR_PARSE - userInfo:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSString stringWithCString:str encoding:NSUTF8StringEncoding], - [NSNumber numberWithInt:lineno], - [NSString stringWithCString:linebuff encoding:NSUTF8StringEncoding], - [NSNumber numberWithInt:tokenpos], - [NSNumber numberWithInt:yyleng], - nil] - forKeys: [NSArray arrayWithObjects:NSLocalizedDescriptionKey, - @"lineNumber", - @"syntaxString", - @"tokenStart", - @"tokenLength", - nil]]]; - - [currentAssembler invalidateWithError:error]; - } -} - -int yywrap() { - return 1; +void yyerror(TikzGraphAssembler *assembler, const char *str) { + [assembler invalidateWithError:str]; } @implementation TikzGraphAssembler - (id)init { + self = nil; + return nil; +} + +- (id)initWithGraph:(Graph*)g { self = [super init]; + if (self) { + graph = [g retain]; + nodeMap = [[NSMutableDictionary alloc] init]; + yylex_init (&scanner); + yyset_extra(self, scanner); + } return self; } - (void)dealloc { [graph release]; + [nodeMap release]; [lastError release]; + yylex_destroy (scanner); [super dealloc]; } -- (Graph*)graph { return graph; } -- (NSError*)lastError { return lastError; } - -- (BOOL)parseTikz:(NSString *)tikz { - return [self parseTikz:tikz forGraph:[Graph graph]]; ++ (BOOL) parseTikz:(NSString*)tikz forGraph:(Graph*)gr { + return [self parseTikz:tikz forGraph:gr error:NULL]; +} ++ (Graph*) parseTikz:(NSString*)tikz error:(NSError**)e { + Graph *gr = [[Graph alloc] init]; + if ([self parseTikz:tikz forGraph:gr error:e]) { + return [gr autorelease]; + } else { + [gr release]; + return nil; + } +} ++ (Graph*) parseTikz:(NSString*)tikz { + return [self parseTikz:tikz error:NULL]; } -- (BOOL)parseTikz:(NSString*)tikz forGraph:(Graph*)gr { - [parseLock lock]; - - lineno = 1; - tokenpos = 0; - NSRange range = [tikz rangeOfString:@"\n"]; ++ (BOOL) parseTikz:(NSString*)tikz forGraph:(Graph*)gr error:(NSError**)error { + + if([tikz length] == 0) { + // empty string -> empty graph + return YES; + } + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + TikzGraphAssembler *assembler = [[self alloc] initWithGraph:gr]; + [assembler autorelease]; + + /* + lineno = 1; + tokenpos = 0; + NSRange range = [tikz rangeOfString:@"\n"]; NSString *firstLine; if (range.length == 0) { firstLine = tikz; @@ -112,49 +100,50 @@ int yywrap() { // first line too long; just terminate it at the end of the buffer linebuff[499] = 0; } + */ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - currentAssembler = self; - - // set the current graph - if (graph != gr) { - [graph release]; - graph = [gr retain]; - } - - // the node map keeps track of the mapping of names to nodes - nodeMap = [[NSMutableDictionary alloc] init]; - - // do the parsing if actual input - if([tikz length] > 0){ - yy_scan_string([tikz UTF8String]); - yyparse(); - yylex_destroy(); - } - - [nodeMap release]; - nodeMap = nil; + yy_scan_string([tikz UTF8String], [assembler scanner]); + int result = yyparse(assembler); - currentAssembler = nil; [pool drain]; - - [parseLock unlock]; - - return (graph != nil); + if (result == 0) { + return YES; + } else { + if (error) { + /* + if (lastError) { + *error = [[lastError retain] autorelease]; + } else + */ + if (result == 1) { + *error = [NSError errorWithMessage:@"Syntax error" + code:TZ_ERR_PARSE]; + } else if (result == 2) { + *error = [NSError errorWithMessage:@"Insufficient memory" + code:TZ_ERR_PARSE]; + } else { + *error = [NSError errorWithMessage:@"Unknown error" + code:TZ_ERR_PARSE]; + } + } + return NO; + } } -- (BOOL)testTikz:(NSString *)tikz{ ++ (BOOL)validateTikzPropertyNameOrValue:(NSString*)tikz { BOOL r; NSString * testTikz = [NSString stringWithFormat: @"{%@}", tikz]; - yy_scan_string([testTikz UTF8String]); - yylex(); - - r = !(yyleng < [testTikz length]); - + void *scanner; + yylex_init (&scanner); + yyset_extra(nil, scanner); + yy_scan_string([testTikz UTF8String], scanner); + YYSTYPE lval; + yylex(&lval, scanner); + r = !(yyget_leng(scanner) < [testTikz length]); + yylex_destroy(scanner); [testTikz autorelease]; - yylex_destroy(); return r; } @@ -165,32 +154,66 @@ int yywrap() { lastError = nil; } -- (void)invalidateWithError:(NSError*)error { - [self invalidate]; - lastError = [error retain]; -} - -+ (void)setup { - parseLock = [[NSLock alloc] init]; -} - -+ (TikzGraphAssembler*)currentAssembler { - return currentAssembler; -} - -+ (TikzGraphAssembler*)assembler { - return [[[TikzGraphAssembler alloc] init] autorelease]; -} - @end @implementation TikzGraphAssembler (Parser) +- (Graph*)graph { return graph; } - (void)addNodeToMap:(Node*)n { [nodeMap setObject:n forKey:[n name]]; } - (Node*)nodeWithName:(NSString*)name { - return [nodeMap objectForKey:name]; + return [nodeMap objectForKey:name]; +} +- (void) newLineStarted:(char *)text { + /* + strncpy(linebuff, yytext+1, 500); + linebuff[499] = 0; // ensure null-terminated + lineno++; + tokenpos = 0; + */ +} +- (void) incrementPosBy:(size_t)amount { + //tokenpos += amount; +} + +- (void) invalidateWithError:(const char *)message { + /* + // if the error is on the first line, treat specially + if([assembler lineNumber] == 1){ + //strcpy(linebuff, yytext+1); + NSLog(@"Problem ahoy!"); + } + + NSString *pointerStrPad = [@"" stringByPaddingToLength:(tokenpos-yyleng) + withString:@" " + startingAtIndex:0]; + NSString *pointerStr = [@"" stringByPaddingToLength:yyleng + withString:@"^" + startingAtIndex:0]; + NSLog(@"Parse error on line %i: %s\n%s\n%@\n", lineno, str, linebuff, + [pointerStrPad stringByAppendingString:pointerStr]); + NSDictionary *userInfo = + [NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithUTF8String:str], + NSLocalizedDescriptionKey, + [NSNumber numberWithInt:lineno], + @"lineNumber", + [NSString stringWithUTF8String:linebuff], + @"syntaxString", + [NSNumber numberWithInt:tokenpos], + @"tokenStart", + [NSNumber numberWithInt:yyleng], + @"tokenLength"]; + NSError *error = + [NSError errorWithDomain:@"net.sourceforge.tikzit" + code:TZ_ERR_PARSE + userInfo:userInfo]; + + lastError = [error retain]; + */ + [self invalidate]; } +- (void*) scanner { return scanner; } @end // vi:ft=objc:ts=4:noet:sts=4:sw=4 -- cgit v1.2.3