// TLRead.m // by David Phillip Oster // September 2007 // // Cocoa centric lisp // // Copyright 2007 David Phillip Oster // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #import "TLLisp.h" // Floating point or int. static TLID *TLReadNumberString(NSString *inp, int *ioStartIndexp) { int iCount = [inp length]; int i = *ioStartIndexp; int e; BOOL hasSeenDecimal= NO; for (e = i;e < iCount; ++e) { unichar c = [inp characterAtIndex:e]; if ( ! ('0' <= c && c <= '9')) { if ( ! hasSeenDecimal && '.' == c) { hasSeenDecimal = YES; } else { break; } } } NSString *s = [inp substringWithRange:NSMakeRange(i, e-i)]; *ioStartIndexp = e; if (hasSeenDecimal) { float f = atof([s UTF8String]); return [NSNumber numberWithFloat:f]; } else { int n = atoi([s UTF8String]); return [NSNumber numberWithInt:n]; } } // to get backslash to work, we build up strings one char at a time. static TLID *TLReadQuotedString(NSString *inp, int *ioStartIndexp) { NSMutableString *val = [NSMutableString string]; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int iCount = [inp length]; int i = *ioStartIndexp; int e; ++i; for (e = i;e < iCount; ++e) { unichar c = [inp characterAtIndex:e]; if (c == '\\' && e < iCount-1) { ++e; c = [inp characterAtIndex:e]; } else if (c == '"') { break; } [val appendString:[NSString stringWithCharacters:&c length:1]]; } [pool release]; *ioStartIndexp = e+1; return val; } // allow atoms like ->, <->, etc. TLID *TLReadAngleAtomString(NSString *inp, int *ioStartIndexp) { int iCount = [inp length]; int i = *ioStartIndexp; int e; for (e = i;e < iCount; ++e) { unichar c = [inp characterAtIndex:e]; if ( ! (c == '-' || c == '=' || c == '<' || c == '>')) { break; } } NSString *s = [inp substringWithRange:NSMakeRange(i, e-i)]; *ioStartIndexp = e; return TLIntern(s); } TLID *TLReadAtomString(NSString *inp, int *ioStartIndexp) { int iCount = [inp length]; int i = *ioStartIndexp; int e; for (e = i;e < iCount; ++e) { unichar c = [inp characterAtIndex:e]; if ((c == '(' || c == ')' || c == '"' || c == '\'' || c == ',') || ! ('!' <= c && c <= 'z')) { break; } } NSString *s = [inp substringWithRange:NSMakeRange(i, e-i)]; *ioStartIndexp = e; return TLIntern(s); } // dispatch to token build base on first character TLID *TLReadTokenString(NSString *inp, int *ioStartIndexp) { TLID *retVal = nil; int i = *ioStartIndexp; int iCount = [inp length]; unichar c, c1; for (;i < iCount; ++i) { c = [inp characterAtIndex:i]; if (c <= ' ') { /* skip */ } else if ('0' <= c && c <= '9') { retVal = TLReadNumberString(inp, &i); break; } else if ('.' == c && i < iCount-1 && '0' <= (c1 = [inp characterAtIndex:i+1]) && c1 <= '9') { retVal = TLReadNumberString(inp, &i); break; } else if (c == '"') { retVal = TLReadQuotedString(inp, &i); break; } else if (c == '-' || c == '=' || c == '<' || c == '>') { retVal = TLReadAngleAtomString(inp, &i); break; } else if (('!' <= c && c <= '/') || ('[' <= c && c <= '`') || ('{' <= c && c <= '~') || c == 0x3BB) { // allow lambda retVal = TLIntern([inp substringWithRange:NSMakeRange(i, 1)]); ++i; break; } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) { retVal = TLReadAtomString(inp, &i); break; } } *ioStartIndexp = i; return retVal; } // call self recursively to build up lists == NSArray TLID *TLReadStringInner(NSString *inp, int *ioStartIndexp) { TLID *val = TLReadTokenString(inp, ioStartIndexp); if (gTLOpenParen == val) { NSMutableArray *retVal = [NSMutableArray array]; for (;;) { val = TLReadStringInner(inp, ioStartIndexp); if (nil == val || gTLCloseParen == val) { break; } [retVal addObject:val]; } val = retVal; } else if (gTLSingleQuote == val) { NSMutableArray *retVal = [NSMutableArray array]; val = TLReadStringInner(inp, ioStartIndexp); if (nil != val) { [retVal addObject:gTLSingleQuote]; [retVal addObject:val]; val = retVal; } } return val; } TLID *TLReadString(NSString *inp) { int startIndex = 0; return TLReadStringInner(inp, &startIndex); } TLID *TLReadFILE(FILE *inp) { char s[512]; NSString *str = [NSString stringWithUTF8String:fgets(s, sizeof s, inp)]; return TLReadString(str); } TLID *TLRead0(void) { return TLReadFILE(stdin); }