This is MiscIfStack.m in view mode; [Download] [Up]
// // MiscIfStack.m -- a simple data container for tracking if/then constructs // Written by Don Yacktman Copyright (c) 1995 by Don Yacktman. // Version 1.0. All rights reserved. // This notice may not be removed from this source code. // // This object is included in the MiscKit by permission from the author // and its use is governed by the MiscKit license, found in the file // "LICENSE.rtf" in the MiscKit distribution. Please refer to that file // for a list of all applicable permissions and restrictions. // #import "_MiscIfPlaceHolder.h" #import <misckit/MiscIfStack.h> @implementation MiscIfStack /*" A MiscIfStack is a specialized stack which may be used in a dynamic interpreter to implement if/then/else/endif constructs. The syntax is expected to have an "endif" match every single "if" token. The "else" token is optional. The "if", "else", and "endif" divide the interpreted code into blocks. The MiscIfStack can tell you whether or not the current block should be executed. This includes correct handling of nested ifs. To use a MiscIfStack, first send a -#{reset} message. Then, whenever an "if" token is encountered in the parsing, send a -#{startIf:} message to the MiscIfStack. If the conditional evaluated true, use YES as the argument. Us NO if it evaluated falsely. When (and if) an "else" token is encountered, send a -#{startElse} message. Finally, when the "endif" toekn is encountered, send a -#{endIf} message. To determine if the current block should be executed, simply query the MiscIfStack with a -#{currentConditionalIsActive} message. If YES is returned, then the code should be executed. "*/ - reset /*" Clears the MiscIfStack. This should be called whenever a new program is started. Returns self. "*/ { [self freeObjects]; [self empty]; return self; } - startIf:(BOOL)isActive /*" Starts an "if" block. If the "if" evaluates to true, then %{isActive} should be YES, NO otherwise. This will be used to determine the current status of the MiscIfStack. Returns self, or nil if an error occurs. "*/ { id tempIf = [[_MiscIfPlaceHolder alloc] init]; [tempIf setIfType:MISC_IF_START]; if ([self currentConditionalIsActive]) { [tempIf setActivity:(isActive ? MISC_IF_ACTIVE : MISC_IF_INACTIVE)]; } else { [tempIf setActivity:MISC_IF_DEAD]; } if ([self pushObject:tempIf]) return self; return nil; } - startElse /*" Begins an "else" block, changing the status to be the opposite of the "if" block this is paired to. Returns "self" if successful and "nil" if an error occurs. Errors include two "else" tokens in a row or an "else" without an accompanying "if" token. "*/ { id tempIf, lastIf = [self lastObject]; Misc_IF_Activity newActivity; if ([lastIf ifType] == MISC_IF_ELSE) { [self doubleElseIfError]; return nil; } if (!lastIf) { [self elseWithoutIfError]; return nil; } tempIf = [[_MiscIfPlaceHolder alloc] init]; [tempIf setIfType:MISC_IF_ELSE]; switch ([lastIf activity]) { case MISC_IF_ACTIVE : newActivity = MISC_IF_INACTIVE; break; case MISC_IF_INACTIVE : newActivity = MISC_IF_ACTIVE; break; // dead ifs stay dead in the else. It means that this if/else // pair is inside of a conditional that evaluated false. default : newActivity = MISC_IF_DEAD; break; } [tempIf setActivity:newActivity]; if ([self pushObject:tempIf]) return self; return nil; } - endIf /*" Ends an "if-else" block, returning the MiscIfStack to the status of the block before the "if" to be cleared was encountered. Returns self if successful and nil if there was an error, such as an "endif" without a matching "if". "*/ { if (![self lastObject]) { // error-- "endif" without "if" [self endWithoutIfError]; return nil; } // Discard an "else" if there is one. if ([[self lastObject] ifType] == MISC_IF_ELSE) { [[self popObject] free]; } // And discard the "if" that matches us. We don't need to check // since the checking when we push guarantees things for us. [[self popObject] free]; return self; } - (BOOL)currentConditionalIsActive /*" Returns YES if the "if" or "else" block on top of the stack evaluates true and should be executed. Returns NO otherwise. "*/ { // Inactive if "dead" or explicitly inactive. Active if explicitly active. if ([self count] < 1) return YES; return ([[self lastObject] activity] == MISC_IF_ACTIVE); } - (void)endWithoutIfError /*" Prints a diagnostic error message to the console if an "endif" token is found that does not have a matching "if" token. "*/ { fprintf(stderr, "MiscIfStack: \"endif\" without \"if\" encountered.\n"); } - (void)elseWithoutIfError /*" Prints a diagnostic error message to the console if an "else" token is found that does not have a matching "if" token. "*/ { fprintf(stderr, "MiscIfStack: \"else\" without \"if\" encountered.\n"); } - (void)doubleElseIfError /*" Prints a diagnostic error message to the console if two "else" tokens are found in a row. This is syntactically the same as having an "else" without a matching "if". "*/ { fprintf(stderr, "MiscIfStack: \"else\" use twice in a row.\n"); } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.