#import "VScheme.h" #import "SchemeDelegate.h" /* #include #include #include */ extern id yyresultform; extern BOOL yyschemeerrflag; NSMutableArray *positionStack = nil; static char *forms[] = { "top", "define1", "define2", "set", "lambda1", "lambda2", "quote", "binding", "let", "let*", "letrec", "if1", "if2", "and", "or", "begin", "apply", "case", "scond1", "scond2", "scond3", "cond", "callcc" }; void print_tree(id item, int indent) { int pos; for(pos=0; pos\n"); } else if(c=='\t'){ printf("CHAR: <\\tab>\n"); } else if(c==' '){ printf("CHAR: <\\space>\n"); } else{ printf("CHAR: <%c>\n", c); } } else if([item isKindOfClass:[Int class]]){ printf("INT: %ld\n", [item intVal]); } else if([item isKindOfClass:[Double class]]){ printf("DOUBLE: %le\n", [item doubleVal]); } else if([item isKindOfClass:[Symbol class]]){ printf("SYMBOL: <%s>\n", [[item symVal] cString]); } else if([item isKindOfClass:[String class]]){ printf("STRING: <%s>\n", [[item strVal] cString]); } else if([item isKindOfClass:[Closure class]]){ printf("CLOSURE %s\n", [[VScheme valToString:[item args]] cString]); } else if([item isKindOfClass:[Primitive class]]){ printf("PRIMITIVE\n"); } else if([item isKindOfClass:[Thunk class]]){ printf("THUNK %d %d %d\n", [item argp], [item envp], [item codep]); } else if([item isKindOfClass:[Pair class]]){ printf("PAIR %s\n", [[VScheme valToString:item] cString]); } else if([item isKindOfClass:[Vector class]]){ printf("VECTOR %s\n", [[VScheme valToString:item] cString]); } else if([item isKindOfClass:[ByteCodes class]]){ printf("CODES: %u\n", [item length]); } else{ printf("FORM %s\n", forms[[item tag]]); if([item arg1]!=nil){ print_tree([item arg1], indent+1); } if([item arg2]!=nil){ print_tree([item arg2], indent+1); } if([item arg3]!=nil){ print_tree([item arg3], indent+1); } } } void print_scheme_item(id item) { print_tree(item, 0); } @implementation VScheme static char *codenames[] = { "TO_ARGS", "LOOKUP", "CHECK_PTC", "POP_ENV", "POP_ARGS", "APPLIC", "LIST_APPLIC", "DEFINE", "SET", "CLOSURE", "IF", "LAYER", "MEMQ", "DUP_ARG", "EXCH_ARGS", "STATE_TO_THUNK", "MARK_THUNK" }; + (NSString *)valToString:(id)item seen:(NSMutableSet *)mem { if(item==[NSNull null]){ return @"()"; } if((isPair(item) || isVector(item)) && [mem containsObject:item]==YES){ return @""; } if(isBoolean(item)){ return ([item boolVal]==YES ? @"#t" : @"#f"); } else if(isChar(item)){ NSString *format; char c = [item charVal]; if(c=='\n'){ format = @"#\\newline"; } else if(c=='\t'){ format = @"#\\tab"; } else if(c==' '){ format = @"#\\space"; } else{ format = @"#\\%c"; } return [NSString stringWithFormat:format, c]; } else if(isInt(item)){ return [NSString stringWithFormat:@"%d", [item intVal]]; } else if(isDouble(item)){ double v = [item doubleVal]; NSString *vstr = [[NSNumber numberWithDouble:v] description]; const char *buf = [vstr cString]; if(*buf && *buf=='-'){ buf++; } while(*buf && isdigit(*buf++)); if(!(*buf)){ vstr = [vstr stringByAppendingString:@".0"]; } return vstr; } else if(isSymbol(item)){ return [NSString stringWithFormat:@"%@", [item symVal]]; } else if(isString(item)){ NSString *str = [item strVal]; int len = [str length]; const char *src; char buf[2*len+1], *dst; src = [str cString]; dst = buf; while(*src){ if(*src=='"'){ *dst++ = '\\'; } *dst++ = *src++; } *dst = 0; return [NSString stringWithFormat:@"\"%s\"", buf]; } else if(isClosure(item)){ return [NSString stringWithFormat:@"", [VScheme valToString:[item args] seen:mem]]; } else if(isPrimitive(item)){ return [NSString stringWithFormat:@"", [item primName]]; } else if(isThunk(item)){ return [NSString stringWithFormat:@"", [item argp], [item envp], [item codep]]; } else if(isPair(item)){ NSString *str; NSMutableSet *local = [NSMutableSet setWithCapacity:1]; NSEnumerator *en; [mem addObject:item]; [local addObject:item]; str = [VScheme valToString:[item car] seen:mem]; item = [item cdr]; while(isPair(item) && [mem containsObject:item]==NO){ [mem addObject:item]; [local addObject:item]; str = [str stringByAppendingFormat:@" %@", [VScheme valToString:[item car] seen:mem]]; item = [item cdr]; } if(isPair(item)){ str = [str stringByAppendingString:@" "]; } else if(item!=[NSNull null]){ str = [str stringByAppendingFormat:@" . %@", [VScheme valToString:item seen:mem]]; } en = [local objectEnumerator]; while((item = [en nextObject])!=nil){ [mem removeObject:item]; } [local removeAllObjects]; return [NSString stringWithFormat:@"(%@)", str]; } else if(isVector(item)){ id *entries = [item entries]; NSString *str; int count = [item count], index; if(!count){ return @"#()"; } [mem addObject:item]; str = [NSString stringWithFormat:@"#(%@", [VScheme valToString:entries[0] seen:mem]]; for(index=1; indexinst.data.coord.x){ imgMin.x = inst.data.coord.x; } if(imgMin.y>inst.data.coord.y){ imgMin.y = inst.data.coord.y; } if(imgMax.xminx){ imgMin.x = minx; } if(imgMin.y>miny){ imgMin.y = miny; } if(imgMax.x=lower){ res = [Pair newCar:[argStack objectAtIndex:pos] Cdr:res]; pos--; } return res; } - pushByteCodes:(ByteCodes *)bcodes { if(curpc==curlength){ [codeStack removeLastObject]; } else{ [pcStack addObject:[NSNumber numberWithInt:curpc]]; } [codeStack addObject:bcodes]; curpc = 0; curcodes = [bcodes codes]; curlength = [bcodes length]; return self; } - interrupt:(id)sender { interrupted = YES; return self; } #define INITIALINT 5 #define INTERVAL 1 - (BOOL)run:(ByteCodes *)prog mode:(PROCESS_MODE)pmode; { NSAutoreleasePool *pool = [NSAutoreleasePool new]; id instr; if(errmsg != nil && [errmsg isKindOfClass:[NSConstantString class]]==NO){ [errmsg release]; errmsg = @""; } codeStack = [NSMutableArray arrayWithCapacity:1]; pcStack = [NSMutableArray arrayWithCapacity:1]; argStack = [NSMutableArray arrayWithCapacity:1]; [codeStack retain]; [pcStack retain]; [argStack retain]; [codeStack addObject:prog]; [prog setRoot:YES]; curcodes = [prog codes]; curpc = 0; curlength = [prog length]; NSApplication *app = [NSApplication sharedApplication]; BOOL inModal = NO; NSDate *interruptDate = [NSDate dateWithTimeIntervalSinceNow:INITIALINT]; NSModalSession interruptSession; NSPanel *interruptPanel = [delegate interruptPanel]; int interruptMask = NSLeftMouseDownMask | NSLeftMouseUpMask | NSLeftMouseDraggedMask; hadOutput = NO; interrupted = NO; [interruptDate retain]; /* struct rusage usg; getrusage(RUSAGE_SELF, &usg); long start = usg.ru_utime.tv_sec; */ #define RESFORITER 4000 unsigned long int iterations = 0; while(1){ iterations++; if(!(iterations % RESFORITER) && pmode!=MODE_LOAD && inModal==NO && [interruptDate timeIntervalSinceNow]<0.0){ [interruptPanel center]; [interruptPanel orderOut:nil]; [interruptPanel flushWindow]; interruptSession = [app beginModalSessionForWindow:interruptPanel]; inModal = YES; [interruptDate release]; interruptDate = [NSDate dateWithTimeIntervalSinceNow:INTERVAL]; [interruptDate retain]; [[NSCursor arrowCursor] push]; } else if(!(iterations % RESFORITER) && inModal==YES && [interruptDate timeIntervalSinceNow]<0.0){ NSDate *evDate = [NSDate dateWithTimeIntervalSinceNow:0.025]; NSEvent *event = [app nextEventMatchingMask:interruptMask untilDate:evDate inMode:NSDefaultRunLoopMode dequeue:YES]; if([event window]==interruptPanel){ [app sendEvent:event]; } if(interrupted==YES){ errflag = YES; errmsg = @"user abort"; break; } else{ [interruptDate release]; interruptDate = [NSDate dateWithTimeIntervalSinceNow:INTERVAL]; [interruptDate retain]; if(output!=nil){ if(hadOutput==NO){ [delegate output:@"\n"]; hadOutput = YES; } [delegate output:output]; [self clearOutput]; } } } if(!(curpcMAXL ? " (...)" : "")]; break; } [positionStack removeLastObject]; id evForms = yyresultform; if(evForms==[NSNull null]){ res = [NSNull null]; break; } // [SCMType addToMarkables:evForms]; ByteCodes *evCodes = [ByteCodes new]; [evCodes setSource:evForms]; errflag = [self compile:[evForms arg1] output:evCodes]; if(errflag==NO){ [evCodes setRoot:YES]; [self pushByteCodes:evCodes]; } } else if(isPrimitive(op)){ if([op evalVM:self Args:argStack offset:offs]==YES){ res = [op value]; } else{ errflag = YES; errmsg = [[NSString alloc] initWithString:[(Primitive *)op errmsg]]; break; } } else if(isThunk(op)){ int argp = [op argp], envp = [op envp], codep = [op codep], curargp = [argStack count], curenvp = [envStack count], curcodep = [codeStack count]; if(argp<0 || envp<0 || codep<0){ errflag = YES; errmsg = @"this thunk has expired"; break; } if(argc!=1){ errflag = YES; errmsg = @"thunk requires a single argument"; break; } res = [argStack lastObject]; while(curargp-->argp){ [argStack removeLastObject]; } while(curenvp-->envp){ [envStack removeLastObject]; } while(curcodep-->codep){ [codeStack removeLastObject]; if(curcodep>codep){ [pcStack removeLastObject]; } } curpc = [[pcStack lastObject] intValue]; [pcStack removeLastObject]; curcodes = [[codeStack lastObject] codes]; } else if(isClosure(op)){ NSMapTable *layer = NSCreateMapTable(NSObjectMapKeyCallBacks, NSNonRetainedObjectMapValueCallBacks, 1); id argl = [op args]; id env; if(isSymbol(argl)){ id list = [self args2list:offs]; [list retain]; NSMapInsert(layer, [argl symVal], list); } else{ int symc = 0; while(isPair(argl)){ symc++; if(symc>argc){ errflag = YES; errmsg = [[NSString alloc] initWithFormat:@"not enough arguments to %@", [VScheme valToString:op]]; break; } id obj = [argStack objectAtIndex:offs++]; [obj retain]; NSMapInsert(layer, [[argl car] symVal], obj); argl = [argl cdr]; } if(symcmaxcode){ maxcode = [codeStack count]; } if([pcStack count]>maxpc){ maxpc = [pcStack count]; } if([argStack count]>maxarg){ maxarg = [argStack count]; } if([envStack count]>maxenv){ maxenv = [envStack count]; } if(errflag==YES){ break; } if([SCMType totalAllocated]>4*[SCMType allocatedAfterGC]){ int ptotal = [SCMType totalAllocated]; NSString *msg, *format = @"\n%@\nGC prev: %d now: %d\n", *cformat = @"%@ prev: %d now: %d\n"; struct { Class cl; int prev; } *cent, classes[] = { { [Pair class], 0 }, { [Environment class], 0 }, { [Int class], 0 }, { [Closure class], 0 }, { [Vector class], 0 }, { [Triple class], 0 }, { [ByteCodes class], 0 }, { [interruptDate class], 0 }, { [NSTableView class], 0 }, { [NSTableColumn class], 0 }, { [NSScrollView class], 0 }, { [SCMTextView class], 0 }, { [NSWindow class], 0 }, { nil, 0 } }; for(cent=classes; cent->cl!=nil; cent++){ cent->prev = GSDebugAllocationCount(cent->cl); } [SCMType nextMark]; [SCMType currentMarkForMarkables]; // [source setMarkToCurrent]; int codeind, codemx = [codeStack count]; for(codeind=0; codeindcl!=nil; cent++){ msg = [NSString stringWithFormat:cformat, NSStringFromClass(cent->cl), cent->prev, GSDebugAllocationCount(cent->cl)]; [delegate statistics:msg]; } [delegate statistics:@"\n"]; } } } if(inModal==YES){ [app endModalSession:interruptSession]; [interruptPanel close]; [NSCursor pop]; } [interruptDate release]; [pool release]; /* getrusage(RUSAGE_SELF, &usg); long end = usg.ru_utime.tv_sec; NSLog(@"%u", end-start); */ return (errflag==YES ? NO : YES); } - special:(id)data output:(ByteCodes *)codes popenv:(int)ec { int tag = [data tag]; switch(tag){ case FORM_DEFINE1: [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[data arg1]]]; [self compile:[data arg2] output:codes popenv:ec]; [codes addTriple:[Triple newTag:IN_DEFINE]]; break; case FORM_DEFINE2: { ByteCodes *body = [ByteCodes new]; [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[[data arg1] car]]]; [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[[data arg1] cdr]]]; [self sequence:[data arg2] output:body popenv:1]; [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:body]]; [codes addTriple:[Triple newTag:IN_CLOSURE]]; if(ec>0){ [codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } [codes addTriple:[Triple newTag:IN_DEFINE]]; } break; case FORM_SET: [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[data arg1]]]; // [self compile:[data arg2] output:codes popenv:ec]; [self compile:[data arg2] output:codes popenv:0]; [codes addTriple:[Triple newTag:IN_SET]]; [codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; break; case FORM_LAMBDA1: case FORM_LAMBDA2: { ByteCodes *body = [ByteCodes new]; [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[data arg1]]]; [self sequence:[data arg2] output:body popenv:1]; [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:body]]; [codes addTriple:[Triple newTag:IN_CLOSURE]]; if(ec>0){ [codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } } break; case FORM_BEGIN: [self sequence:[data arg1] output:codes popenv:ec]; break; case FORM_APPLY: [self compile:[data arg1] output:codes popenv:0]; [codes addTriple:[Triple newTag:IN_CHECK_PTC]]; [self compile:[data arg2] output:codes popenv:ec]; [codes addTriple:[Triple newTag:IN_LIST_APPLIC]]; break; case FORM_QUOTE: if(ec>0){ [codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[data arg1]]]; break; case FORM_CALLCC:{ Thunk *t = [Thunk newArgp:-1 Envp:-1 Codep:-1]; [codes addTriple:[Triple newTag:IN_STATE_TO_THUNK Arg1:t]]; [self compile:[data arg1] output:codes popenv:ec]; [codes addTriple:[Triple newTag:IN_CHECK_PTC]]; [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:t]]; [codes addTriple:[Triple newTag:IN_APPLIC IntArg1:1]]; [codes addTriple:[Triple newTag:IN_MARK_THUNK Arg1:t]]; } break; case FORM_LET: case FORM_LETSTAR: case FORM_LETREC:{ int count = 0; id bindings = [data arg1]; if(tag==FORM_LETREC){ [codes addTriple:[Triple newTag:IN_LAYER IntArg1:0]]; } while(isPair(bindings)){ id binding = [bindings car]; [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[binding arg1]]]; [self compile:[binding arg2] output:codes popenv:0]; if(tag==FORM_LETREC){ [codes addTriple:[Triple newTag:IN_DEFINE]]; [codes addTriple:[Triple newTag:IN_POP_ARGS IntArg1:1]]; } else if(tag==FORM_LETSTAR){ [codes addTriple:[Triple newTag:IN_LAYER IntArg1:1]]; } count++; bindings = [bindings cdr]; } if(tag==FORM_LET){ [codes addTriple:[Triple newTag:IN_LAYER IntArg1:count]]; } [self sequence:[data arg2] output:codes popenv:ec+(tag==FORM_LETSTAR? count : 1)]; } break; case FORM_IF1: case FORM_IF2: { ByteCodes *trueClause = [ByteCodes new], *falseClause = [ByteCodes new]; [self compile:[data arg1] output:codes popenv:0]; [self compile:[data arg2] output:trueClause popenv:ec]; if([data arg3]!=nil){ [self compile:[data arg3] output:falseClause popenv:ec]; } else{ if(ec>0){ [falseClause addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } [falseClause addTriple:[Triple newTag:IN_TO_ARGS Arg1:[NSNull null]]]; } // [trueClause retain]; [falseClause retain]; [codes addTriple:[Triple newTag:IN_IF Arg1:trueClause Arg2:falseClause]]; } break; case FORM_COND: { ByteCodes *current, *endClause = [ByteCodes new]; id args, curcond; args = [data arg1]; curcond = [args car]; if(isPair(curcond)){ [self sequence:[curcond cdr] output:endClause popenv:ec]; args = [args cdr]; } else{ if(ec>0){ [endClause addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } [endClause addTriple:[Triple newTag:IN_TO_ARGS Arg1:[NSNull null]]]; } current = endClause; // [current retain]; while(isPair(args)){ ByteCodes *clause = [ByteCodes new], *match = [ByteCodes new]; int tag; curcond = [args car]; tag = [curcond tag]; [self compile:[curcond arg1] output:clause popenv:0]; if(tag==FORM_SCOND1){ [clause addTriple:[Triple newTag:IN_DUP_ARG]]; [match addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } else if(tag==FORM_SCOND2){ [self sequence:[curcond arg2] output:match popenv:ec]; } else{ [clause addTriple:[Triple newTag:IN_DUP_ARG]]; [self compile:[curcond arg2] output:match popenv:ec]; [match addTriple:[Triple newTag:IN_CHECK_PTC]]; [match addTriple:[Triple newTag:IN_EXCH_ARGS]]; [match addTriple:[Triple newTag:IN_APPLIC IntArg1:1]]; [current prependTriple: [Triple newTag:IN_POP_ARGS IntArg1:1]]; } [clause addTriple: [Triple newTag:IN_IF Arg1:match Arg2:current]]; current = clause; // [current retain]; args = [args cdr]; } [codes appendByteCodes:current]; } break; case FORM_CASE: { ByteCodes *endClause = [ByteCodes new]; id current, args, curcase; args = [data arg2]; curcase = [args car]; [endClause addTriple:[Triple newTag:IN_POP_ARGS IntArg1:1]]; if([curcase car]==[NSNull null]){ [self sequence:[curcase cdr] output:endClause popenv:ec]; args = [args cdr]; } else{ if(ec>0){ [endClause addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } [endClause addTriple:[Triple newTag:IN_TO_ARGS Arg1:[NSNull null]]]; } [self compile:[data arg1] output:codes popenv:0]; current = endClause; while(isPair(args)){ ByteCodes *clause = [ByteCodes new], *match = [ByteCodes new]; curcase = [args car]; [clause addTriple:[Triple newTag:IN_TO_ARGS Arg1:[curcase car]]]; [clause addTriple:[Triple newTag:IN_MEMQ]]; [match addTriple:[Triple newTag:IN_POP_ARGS IntArg1:1]]; [self sequence:[curcase cdr] output:match popenv:ec]; [clause addTriple: [Triple newTag:IN_IF Arg1:match Arg2:current]]; current = clause; // [current retain]; args = [args cdr]; } [codes appendByteCodes:current]; } break; case FORM_AND: case FORM_OR: { ByteCodes *trueClause = [ByteCodes new], *falseClause = [ByteCodes new], *current; id args; if(ec>0){ [trueClause addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } [trueClause addTriple:[Triple newTag:IN_TO_ARGS Arg1:[[Boolean alloc] initSCMBoolean:YES]]]; if(ec>0){ [falseClause addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } [falseClause addTriple:[Triple newTag:IN_TO_ARGS Arg1:[[Boolean alloc] initSCMBoolean:NO]]]; current = (tag == FORM_AND ? trueClause : falseClause); args = [data arg1]; while(isPair(args)){ ByteCodes *clause = [ByteCodes new]; [self compile:[args car] output:clause popenv:0]; if(tag == FORM_AND){ [clause addTriple: [Triple newTag:IN_IF Arg1:current Arg2:falseClause]]; } else{ [clause addTriple: [Triple newTag:IN_IF Arg1:trueClause Arg2:current]]; } current = clause; // [current retain]; args = [args cdr]; } [codes appendByteCodes:current]; } break; default: errflag = YES; errmsg = [[NSString alloc] initWithFormat:@"scheme form unknown (tag %d)" locale: nil, [data tag]]; } } - sequence:(id)data output:(ByteCodes *)codes popenv:(int)ec { while(isPair(data)){ BOOL beforeLast = isPair([data cdr]); [self compile:[data car] output:codes popenv:(beforeLast==YES ? 0 : ec)]; if(beforeLast==YES){ [codes addTriple:[Triple newTag:IN_POP_ARGS IntArg1:1]]; } data = [data cdr]; } } - compile:(id)data output:(ByteCodes *)codes popenv:(int)ec { BOOL application = NO; int count = 0; if(isTriple(data)){ return [self special:data output:codes popenv:ec]; } else if(isPair(data)){ application = YES; while(isPair(data)){ [self compile:[data car] output:codes popenv:0]; count++; if(count==1){ [codes addTriple:[Triple newTag:IN_CHECK_PTC]]; } data = [data cdr]; } } else if(isSymbol(data)){ [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:data]]; [codes addTriple:[Triple newTag:IN_LOOKUP]]; } else{ [codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:data]]; } if(ec>0){ [codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]]; } if(application){ [codes addTriple:[Triple newTag:IN_APPLIC IntArg1:(count-1)]]; } } - (BOOL)compile:(id)data output:(ByteCodes *)codes { errflag = NO; errmsg = @""; [self compile:data output:codes popenv:0]; return errflag; } void yyrestart(FILE *); extern char *yyinputstr, *yyinputstart; extern int yysofar; extern int yyinputline; extern int yyinputitem; - parse:(NSString *)scmText { yyinputline = 0; yyinputitem = 0; yyschemeerrflag = NO; if(positionStack==nil){ positionStack = [NSMutableArray arrayWithCapacity:1]; [positionStack retain]; } [positionStack addObject:[NSMutableArray arrayWithCapacity:1]]; yyinputstr = yyinputstart = (char *)[[scmText stringByAppendingString:@"\n"] cString]; yysofar = 0; yyrestart(NULL); yyparse(); return self; } #define STATS @"code: %d %d (%d) args: %d (%d) envs: %d (%d)\n" #define PARSE_ERROR @"Parse error at item %d, line %d%@.\n" - (BOOL)processString:(NSString *)data mode:(PROCESS_MODE)pmode { [self parse:data]; id forms; int curitem = 0, curpos = 0, nextpos = 0; errpos = -1; if(yyschemeerrflag==YES){ errmsg = [[NSString alloc] initWithFormat:PARSE_ERROR, yyinputitem+1, yyinputline+1, (yysofar==[data length]+1 ? @" (at end)" : @"")]; errflag = YES; errpos = yysofar-1; if(delegate!=nil && pmode!=MODE_LOAD && [delegate respondsToSelector:@selector(result:)]){ [delegate result:[NSNull null]]; } return NO; } [SCMType addToMarkables:yyresultform]; forms = yyresultform; if(forms==[NSNull null]){ [delegate result:[NSNull null]]; } char *yyips = yyinputstart; id yyrf = yyresultform; while(forms!=[NSNull null]){ yyinputstart = yyips; ByteCodes *codes = [ByteCodes new]; BOOL err = [self compile:[forms arg1] output:codes]; // [VScheme printCodes:codes]; NSRange range; int lower, upper; char *first, *fp; int flen; #define MAXLINE 41 #define CENTER " ... " #define HALF ((MAXLINE-5)/2) char second[MAXLINE+1]; range = [[[positionStack lastObject] objectAtIndex:curitem] rangeValue]; nextpos = range.location; lower = curpos; while(isspace(yyinputstart[lower])){ lower++; } upper = nextpos; while(isspace(yyinputstart[upper])){ upper--; } first = fp = malloc(upper-lower+2); while(lower<=upper){ if(isspace(yyinputstart[lower])){ BOOL foundRet = NO; int len=0; while(isspace(yyinputstart[lower]) && lower<=upper){ if(yyinputstart[lower]=='\n'){ foundRet = YES; } lower++; len++; } if(foundRet==YES){ *fp++ = ' '; } else{ strncpy(fp, yyinputstart+lower-len, len); fp += len; } } else{ *fp++ = yyinputstart[lower]; lower++; } } *fp = 0; if((flen=strlen(first))<=MAXLINE){ strcpy(second, first); } else{ strncpy(second, first, HALF); strcpy(second+HALF, CENTER); strcpy(second+HALF+5, first+flen-HALF); } curitem++; curpos = nextpos; if(err==NO){ [self clearOutput]; [self clearImage]; if(pmode==MODE_EVALUATE){ [delegate input:[NSString stringWithCString:second]]; } BOOL runResult = [self run:codes mode:pmode]; if(pmode!=MODE_LOAD){ if([output length]>0){ if(hadOutput==NO){ [delegate output:@"\n"]; } [delegate output:output]; } if(atImgStart==NO){ [self produceImage]; } } if(runResult==YES){ NSString *msg; if(pmode!=MODE_LOAD){ [delegate result:[argStack lastObject]]; } if(delegate!=nil && [delegate respondsToSelector:@selector(statistics:)]){ msg = [NSString stringWithFormat:STATS, [codeStack count], maxpc, maxcode, [argStack count], maxarg, [envStack count], maxenv]; [delegate statistics:msg]; } } [self resetStacks]; [envStack removeObjectsInRange: NSMakeRange(1, [envStack count]-1)]; } free(first); forms = [forms arg2]; if(errflag==YES){ break; } } [positionStack removeLastObject]; [SCMType removeFromMarkables:yyrf]; if(errflag==YES){ [delegate result:[NSNull null]]; [delegate statistics:errmsg]; [delegate statistics:@"\n"]; } // [positions release]; return (errflag == YES ? NO : YES); } @end @implementation SCMImageView - (id)initWithFrame:(NSRect)frameRect { image = nil; return [super initWithFrame:frameRect]; } - (NSImage *)image { return image; } - setImage:(NSImage *)anImage { if(image!=nil){ [image release]; } image = anImage; if(image!=nil){ [image retain]; } [self setNeedsDisplay:YES]; return self; } - (void)drawRect:(NSRect)aRect { if(image!=nil){ [image compositeToPoint:aRect.origin fromRect:aRect operation:NSCompositeCopy]; } } @end