From 8df8317413603dfd1cd7befd838747d47cc43635 Mon Sep 17 00:00:00 2001 From: Kim Wittenburg Date: Sat, 6 Sep 2014 01:54:15 +0200 Subject: [PATCH] Started to Implement the Parser --- MathPad.xcodeproj/project.pbxproj | 146 ++++++++++++++++++++++++++---- MathPad/MPArrayCache.h | 34 +++++++ MathPad/MPArrayCache.m | 59 ++++++++++++ MathPad/MPExpressionEvaluator.h | 30 ++++++ MathPad/MPExpressionEvaluator.m | 56 ++++++++++++ MathPad/MPMath.h | 20 ++++ MathPad/MPMath.lm | 16 ++++ MathPad/MPMath.ym | 126 ++++++++++++++++++++++++++ MathPad/MPParsedElement.h | 39 ++++++++ MathPad/MPParsedElement.m | 60 ++++++++++++ 10 files changed, 570 insertions(+), 16 deletions(-) create mode 100644 MathPad/MPArrayCache.h create mode 100644 MathPad/MPArrayCache.m create mode 100644 MathPad/MPExpressionEvaluator.h create mode 100644 MathPad/MPExpressionEvaluator.m create mode 100644 MathPad/MPMath.h create mode 100644 MathPad/MPMath.lm create mode 100644 MathPad/MPMath.ym create mode 100644 MathPad/MPParsedElement.h create mode 100644 MathPad/MPParsedElement.m diff --git a/MathPad.xcodeproj/project.pbxproj b/MathPad.xcodeproj/project.pbxproj index 25003a0..408db93 100644 --- a/MathPad.xcodeproj/project.pbxproj +++ b/MathPad.xcodeproj/project.pbxproj @@ -29,6 +29,10 @@ 3BBBA3951905704200824E74 /* MPRangeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBBA3941905704200824E74 /* MPRangeTests.m */; }; 3BC4660B19B2425A0033F13A /* MPDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3BF9978318DE623E009CF6C4 /* MPDocument.xib */; }; 3BC4661419B245C60033F13A /* Fonts in Resources */ = {isa = PBXBuildFile; fileRef = 3BC4661319B245C60033F13A /* Fonts */; }; + 3BC46B4919B38C980033F13A /* MPExpressionEvaluator.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BC46B4819B38C980033F13A /* MPExpressionEvaluator.m */; }; + 3BC46B5E19B8BE760033F13A /* MPMath.lm in Sources */ = {isa = PBXBuildFile; fileRef = 3BC46B5D19B8BE760033F13A /* MPMath.lm */; }; + 3BD98B2519B8F0670035852A /* MPMath.ym in Sources */ = {isa = PBXBuildFile; fileRef = 3BD98B2419B8F0670035852A /* MPMath.ym */; }; + 3BE9C4B319B9CC70002CC508 /* MPParsedElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BE9C4B219B9CC70002CC508 /* MPParsedElement.m */; }; 3BF9976F18DE623E009CF6C4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BF9976E18DE623E009CF6C4 /* Cocoa.framework */; }; 3BF9977918DE623E009CF6C4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3BF9977718DE623E009CF6C4 /* InfoPlist.strings */; }; 3BF9977B18DE623E009CF6C4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BF9977A18DE623E009CF6C4 /* main.m */; }; @@ -43,6 +47,33 @@ 3BFAC39C1997BC7600B3EF67 /* NSString+MPExpressionElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BFAC39B1997BC7600B3EF67 /* NSString+MPExpressionElement.m */; }; /* End PBXBuildFile section */ +/* Begin PBXBuildRule section */ + 3B225D2F19B9105E00520A4D /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + filePatterns = "*.lm"; + fileType = pattern.proxy; + isEditable = 1; + outputFiles = ( + "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).yy.h", + "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).yy.m", + ); + script = "cd \"$INPUT_FILE_DIR\"\nflex -o \"$DERIVED_SOURCES_DIR/$INPUT_FILE_BASE.yy.m\" --header-file=\"$DERIVED_SOURCES_DIR/$INPUT_FILE_BASE.yy.h\" \"$INPUT_FILE_NAME\""; + }; + 3B225D3019B9154A00520A4D /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + filePatterns = "*.ym"; + fileType = pattern.proxy; + isEditable = 1; + outputFiles = ( + "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).tab.h", + "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).tab.m", + ); + script = "cd \"$INPUT_FILE_DIR\"\nbison -o \"$DERIVED_SOURCES_DIR/$INPUT_FILE_BASE.tab.m\" --defines=\"$DERIVED_SOURCES_DIR/$INPUT_FILE_BASE.tab.h\" \"$INPUT_FILE_NAME\""; + }; +/* End PBXBuildRule section */ + /* Begin PBXContainerItemProxy section */ 3BF9979318DE623E009CF6C4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -57,6 +88,10 @@ 3B0F69A719028BC600817707 /* MPException.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPException.h; sourceTree = ""; }; 3B0F69A819028C6000817707 /* MPException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPException.m; sourceTree = ""; }; 3B0F69AB1902A82C00817707 /* MPExpressionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionTests.m; sourceTree = ""; }; + 3B225D2C19B90F6A00520A4D /* MPMath.yy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPMath.yy.m; path = "../../../../Library/Developer/Xcode/DerivedData/MathPad-egifwdrtxebksadhtzugiovuvzcy/Build/Intermediates/MathPad.build/Debug/MathPad.build/DerivedSources/MPMath.yy.m"; sourceTree = ""; }; + 3B225D3119B9162E00520A4D /* MPMath.yy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MPMath.yy.h; path = "../../../../Library/Developer/Xcode/DerivedData/MathPad-egifwdrtxebksadhtzugiovuvzcy/Build/Intermediates/MathPad.build/Debug/MathPad.build/DerivedSources/MPMath.yy.h"; sourceTree = ""; }; + 3B225D3219B9168600520A4D /* MPMath.tab.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MPMath.tab.m; path = "../../../../Library/Developer/Xcode/DerivedData/MathPad-egifwdrtxebksadhtzugiovuvzcy/Build/Intermediates/MathPad.build/Debug/MathPad.build/DerivedSources/MPMath.tab.m"; sourceTree = ""; }; + 3B225D3419B916D000520A4D /* MPMath.tab.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MPMath.tab.h; path = "../../../../Library/Developer/Xcode/DerivedData/MathPad-egifwdrtxebksadhtzugiovuvzcy/Build/Intermediates/MathPad.build/Debug/MathPad.build/DerivedSources/MPMath.tab.h"; sourceTree = ""; }; 3B528D0D199417740054DB5F /* MPLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLayout.h; sourceTree = ""; }; 3B528D0E199417E10054DB5F /* MPExpressionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionLayout.h; sourceTree = ""; }; 3B528D0F199417E10054DB5F /* MPExpressionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionLayout.m; sourceTree = ""; }; @@ -78,10 +113,19 @@ 3BB09EDD190728220080A5ED /* NSIndexPath+MPAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexPath+MPAdditions.m"; sourceTree = ""; }; 3BB09EDF190736160080A5ED /* MPSumFunctionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSumFunctionLayout.h; sourceTree = ""; }; 3BB09EE0190736160080A5ED /* MPSumFunctionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSumFunctionLayout.m; sourceTree = ""; }; - 3BBBA3591903EA9B00824E74 /* MPModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPModel.h; sourceTree = ""; }; 3BBBA38419047FC900824E74 /* MPView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPView.h; sourceTree = ""; }; 3BBBA3941905704200824E74 /* MPRangeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRangeTests.m; sourceTree = ""; }; 3BC4661319B245C60033F13A /* Fonts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Fonts; sourceTree = ""; }; + 3BC4661519B365070033F13A /* MPArrayCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPArrayCache.h; sourceTree = ""; }; + 3BC4661619B365070033F13A /* MPArrayCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPArrayCache.m; sourceTree = ""; }; + 3BC46B4719B38C980033F13A /* MPExpressionEvaluator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPExpressionEvaluator.h; sourceTree = ""; }; + 3BC46B4819B38C980033F13A /* MPExpressionEvaluator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPExpressionEvaluator.m; sourceTree = ""; }; + 3BC46B5D19B8BE760033F13A /* MPMath.lm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = MPMath.lm; sourceTree = ""; }; + 3BD98B1E19B8CE490035852A /* libl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libl.a; path = ../../../../../usr/lib/libl.a; sourceTree = ""; }; + 3BD98B2419B8F0670035852A /* MPMath.ym */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = MPMath.ym; sourceTree = ""; }; + 3BE9C4B019B91978002CC508 /* MPMath.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPMath.h; sourceTree = ""; }; + 3BE9C4B119B9CC70002CC508 /* MPParsedElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPParsedElement.h; sourceTree = ""; }; + 3BE9C4B219B9CC70002CC508 /* MPParsedElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPParsedElement.m; sourceTree = ""; }; 3BF9976B18DE623E009CF6C4 /* MathPad.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MathPad.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3BF9976E18DE623E009CF6C4 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 3BF9977118DE623E009CF6C4 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; @@ -113,8 +157,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 3B74BFB319A4C51800E5B5DE /* CoreText.framework in Frameworks */, 3BF9976F18DE623E009CF6C4 /* Cocoa.framework in Frameworks */, + 3B74BFB319A4C51800E5B5DE /* CoreText.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -133,21 +177,10 @@ 3B87E350190082B300259938 /* Model */ = { isa = PBXGroup; children = ( - 3BBBA3591903EA9B00824E74 /* MPModel.h */, - 3BFAC38D1997B61300B3EF67 /* MPExpression.h */, - 3BFAC38E1997B61300B3EF67 /* MPExpression.m */, - 3BFAC3961997B67400B3EF67 /* MPExpressionElement.h */, - 3B87E35E19009D5F00259938 /* MPFunction.h */, - 3B87E35F19009D5F00259938 /* MPFunction.m */, - 3BFAC39A1997BC7600B3EF67 /* NSString+MPExpressionElement.h */, - 3BFAC39B1997BC7600B3EF67 /* NSString+MPExpressionElement.m */, - 3B87E35B1900933200259938 /* MPRangePath.h */, - 3B87E35C1900933200259938 /* MPRangePath.m */, - 3BB09EDC190728220080A5ED /* NSIndexPath+MPAdditions.h */, - 3BB09EDD190728220080A5ED /* NSIndexPath+MPAdditions.m */, - 3B0F69A719028BC600817707 /* MPException.h */, - 3B0F69A819028C6000817707 /* MPException.m */, + 3BC46B4B19B38CB60033F13A /* Base Expression Classes */, + 3BC46B4C19B38CD20033F13A /* Independant Classes */, 3BB09EBC1905EF210080A5ED /* Functions */, + 3BC46B4D19B38CFB0033F13A /* Helpers */, ); name = Model; sourceTree = ""; @@ -225,6 +258,76 @@ name = "Function Layouts"; sourceTree = ""; }; + 3BC4661819B3692A0033F13A /* Temp */ = { + isa = PBXGroup; + children = ( + 3BC4661519B365070033F13A /* MPArrayCache.h */, + 3BC4661619B365070033F13A /* MPArrayCache.m */, + ); + name = Temp; + sourceTree = ""; + }; + 3BC46B4B19B38CB60033F13A /* Base Expression Classes */ = { + isa = PBXGroup; + children = ( + 3BFAC38D1997B61300B3EF67 /* MPExpression.h */, + 3BFAC38E1997B61300B3EF67 /* MPExpression.m */, + 3BFAC3961997B67400B3EF67 /* MPExpressionElement.h */, + 3B87E35E19009D5F00259938 /* MPFunction.h */, + 3B87E35F19009D5F00259938 /* MPFunction.m */, + 3BC46B4F19B506F20033F13A /* Evaluation */, + ); + name = "Base Expression Classes"; + sourceTree = ""; + }; + 3BC46B4C19B38CD20033F13A /* Independant Classes */ = { + isa = PBXGroup; + children = ( + 3B87E35B1900933200259938 /* MPRangePath.h */, + 3B87E35C1900933200259938 /* MPRangePath.m */, + 3B0F69A719028BC600817707 /* MPException.h */, + 3B0F69A819028C6000817707 /* MPException.m */, + ); + name = "Independant Classes"; + sourceTree = ""; + }; + 3BC46B4D19B38CFB0033F13A /* Helpers */ = { + isa = PBXGroup; + children = ( + 3BFAC39A1997BC7600B3EF67 /* NSString+MPExpressionElement.h */, + 3BFAC39B1997BC7600B3EF67 /* NSString+MPExpressionElement.m */, + 3BB09EDC190728220080A5ED /* NSIndexPath+MPAdditions.h */, + 3BB09EDD190728220080A5ED /* NSIndexPath+MPAdditions.m */, + ); + name = Helpers; + sourceTree = ""; + }; + 3BC46B4F19B506F20033F13A /* Evaluation */ = { + isa = PBXGroup; + children = ( + 3BC46B5D19B8BE760033F13A /* MPMath.lm */, + 3BD98B2419B8F0670035852A /* MPMath.ym */, + 3BE9C4B019B91978002CC508 /* MPMath.h */, + 3BD98B2619B8F3F10035852A /* Generated */, + 3BC46B4719B38C980033F13A /* MPExpressionEvaluator.h */, + 3BC46B4819B38C980033F13A /* MPExpressionEvaluator.m */, + 3BE9C4B119B9CC70002CC508 /* MPParsedElement.h */, + 3BE9C4B219B9CC70002CC508 /* MPParsedElement.m */, + ); + name = Evaluation; + sourceTree = ""; + }; + 3BD98B2619B8F3F10035852A /* Generated */ = { + isa = PBXGroup; + children = ( + 3B225D3119B9162E00520A4D /* MPMath.yy.h */, + 3B225D2C19B90F6A00520A4D /* MPMath.yy.m */, + 3B225D3419B916D000520A4D /* MPMath.tab.h */, + 3B225D3219B9168600520A4D /* MPMath.tab.m */, + ); + name = Generated; + sourceTree = ""; + }; 3BF9976218DE623E009CF6C4 = { isa = PBXGroup; children = ( @@ -247,6 +350,7 @@ 3BF9976D18DE623E009CF6C4 /* Frameworks */ = { isa = PBXGroup; children = ( + 3BD98B1E19B8CE490035852A /* libl.a */, 3B74BFB219A4C51800E5B5DE /* CoreText.framework */, 3BF9976E18DE623E009CF6C4 /* Cocoa.framework */, 3BF9979018DE623E009CF6C4 /* XCTest.framework */, @@ -268,6 +372,7 @@ 3BF9977418DE623E009CF6C4 /* MathPad */ = { isa = PBXGroup; children = ( + 3BC4661819B3692A0033F13A /* Temp */, 3B87E350190082B300259938 /* Model */, 3B87E351190082BB00259938 /* View */, 3B87E352190082C000259938 /* Controller */, @@ -320,6 +425,8 @@ 3BF9976918DE623E009CF6C4 /* Resources */, ); buildRules = ( + 3B225D3019B9154A00520A4D /* PBXBuildRule */, + 3B225D2F19B9105E00520A4D /* PBXBuildRule */, ); dependencies = ( ); @@ -368,6 +475,7 @@ knownRegions = ( en, Base, + English, ); mainGroup = 3BF9976218DE623E009CF6C4; productRefGroup = 3BF9976C18DE623E009CF6C4 /* Products */; @@ -409,8 +517,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3BE9C4B319B9CC70002CC508 /* MPParsedElement.m in Sources */, 3B688D9919982DF50006B4AB /* MPLayout.m in Sources */, + 3BD98B2519B8F0670035852A /* MPMath.ym in Sources */, + 3BC46B5E19B8BE760033F13A /* MPMath.lm in Sources */, 3BB09EE1190736160080A5ED /* MPSumFunctionLayout.m in Sources */, + 3BC46B4919B38C980033F13A /* MPExpressionEvaluator.m in Sources */, 3B87E3561900856F00259938 /* MPExpressionView.m in Sources */, 3BB09EC91906FD830080A5ED /* MPSumFunction.m in Sources */, 3BB09EB21905DE500080A5ED /* MPExpressionStorage.m in Sources */, @@ -571,6 +683,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "MathPad/MathPad-Prefix.pch"; INFOPLIST_FILE = "MathPad/MathPad-Info.plist"; @@ -584,6 +697,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "MathPad/MathPad-Prefix.pch"; INFOPLIST_FILE = "MathPad/MathPad-Info.plist"; diff --git a/MathPad/MPArrayCache.h b/MathPad/MPArrayCache.h new file mode 100644 index 0000000..f8fb8ef --- /dev/null +++ b/MathPad/MPArrayCache.h @@ -0,0 +1,34 @@ +// +// MPArrayCache.h +// MathPad +// +// Created by Kim Wittenburg on 31.08.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import + +// A wrapper around NSCache to support index-based caches. Indexes are +// automatically adjusted to represent array-like behaviours. +@interface MPArrayCache : NSObject { + @private + NSCache *_cache; +} + +- (id)init; /* designated initializer */ + +- (void)cacheObject:(id)object + forIndex:(NSUInteger)index; +- (id)cachedObjectForIndex:(NSUInteger)index; + +- (void)clearCacheAtIndex:(NSUInteger)index + replacementLength:(NSUInteger)replacementLength; +- (void)clearCacheInRange:(NSRange)range + replacementLength:(NSUInteger)replacementLength; + +- (void)replaceCachedObjectAtIndex:(NSUInteger)index + withObjects:(NSArray *)objects; +- (void)replaceCachedObjectsInRange:(NSRange)range + withObjects:(NSArray *)objects; + +@end diff --git a/MathPad/MPArrayCache.m b/MathPad/MPArrayCache.m new file mode 100644 index 0000000..50116c4 --- /dev/null +++ b/MathPad/MPArrayCache.m @@ -0,0 +1,59 @@ +// +// MPArrayCache.m +// MathPad +// +// Created by Kim Wittenburg on 31.08.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPArrayCache.h" + +@implementation MPArrayCache { + NSUInteger lastIndex; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + lastIndex = 0; + _cache = [[NSCache alloc] init]; + } + return self; +} + +- (void)cacheObject:(id)object + forIndex:(NSUInteger)index +{ + [_cache setObject:object + forKey:@(index)]; + if (index > lastIndex) { + lastIndex = index; + } +} + +- (id)cachedObjectForIndex:(NSUInteger)index +{ + return [_cache objectForKey:@(index)]; +} + +- (void)clearCacheAtIndex:(NSUInteger)index replacementLength:(NSUInteger)replacementLength +{ + [_cache removeObjectForKey:@(index)]; + for (NSUInteger i = index+1; i < lastIndex; i++) { + id object = [_cache objectForKey:@(i)]; + if (object) { + [_cache removeObjectForKey:@(i)]; + } + } + lastIndex += replacementLength - 1; +} + +- (void)clearCacheInRange:(NSRange)range replacementLength:(NSUInteger)replacementLength; + +- (void)replaceCachedObjectAtIndex:(NSUInteger)index + withObjects:(NSArray *)objects; +- (void)replaceCachedObjectsInRange:(NSRange)range + withObjects:(NSArray *)objects; + +@end diff --git a/MathPad/MPExpressionEvaluator.h b/MathPad/MPExpressionEvaluator.h new file mode 100644 index 0000000..b14d055 --- /dev/null +++ b/MathPad/MPExpressionEvaluator.h @@ -0,0 +1,30 @@ +// +// MPExpressionEvaluator.h +// MathPad +// +// Created by Kim Wittenburg on 31.08.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import +#import "MPExpression.h" + +@class MPExpressionEvaluator, MPExpression, MPParsedElement; + +@interface MPExpressionEvaluator : NSObject + +- (instancetype)initWithExpression:(MPExpression *)expression; + +@property (readonly, nonatomic, strong) MPExpression *expression; + +#pragma mark Lexing +- (MPParsedElement *)structuredRepresentationOfElementAtIndex:(NSUInteger)index; + +#pragma mark Evaluating Expressions +@property (readonly, nonatomic, strong) NSDictionary *variableBindings; + +- (void)bindValue:(double)value toVariableName:(NSString *)name; + +- (double)evaluateWithError:(NSError *__autoreleasing *)error; + +@end diff --git a/MathPad/MPExpressionEvaluator.m b/MathPad/MPExpressionEvaluator.m new file mode 100644 index 0000000..d05081a --- /dev/null +++ b/MathPad/MPExpressionEvaluator.m @@ -0,0 +1,56 @@ +// +// MPExpressionEvaluator.m +// MathPad +// +// Created by Kim Wittenburg on 31.08.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPExpressionEvaluator.h" +#import "MPExpression.h" + +#import "MPParsedElement.h" +#import "MPMath.h" + +@implementation MPExpressionEvaluator { + NSMutableDictionary *_variableBindings; +} +- (id)initWithExpression:(MPExpression *)expression +{ + self = [super init]; + if (self) { + _expression = expression; + _variableBindings = [[NSMutableDictionary alloc] init]; + } + return self; +} + +#pragma mark Lexing +- (MPParsedElement *)structuredRepresentationOfElementAtIndex:(NSUInteger)index +{ + NSString *string = (NSString *)[self.expression elementAtIndex:index]; + YY_BUFFER_STATE buffer = yy_scan_string(string.UTF8String); + yyparse(); + yy_delete_buffer(buffer); + return [parseResult copy]; +} + +#pragma mark Evaluating Expressions +- (NSDictionary *)variableBindings +{ + return [_variableBindings copy]; +} + +- (void)bindValue:(double)value toVariableName:(NSString *)name +{ + [_variableBindings setObject:@(value) + forKey:name]; +} + +- (double)evaluateWithError:(NSError *__autoreleasing *)error +{ + MPParsedElement *element = [self structuredRepresentationOfElementAtIndex:0]; + return element.standaloneValue; +} + +@end diff --git a/MathPad/MPMath.h b/MathPad/MPMath.h new file mode 100644 index 0000000..713948f --- /dev/null +++ b/MathPad/MPMath.h @@ -0,0 +1,20 @@ +// +// YYParse.h +// MathPad +// +// Created by Kim Wittenburg on 05.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPMath.yy.h" +#import "MPMath.tab.h" +#import "MPParsedElement.h" + +#ifndef MathPad_YYParse_h +#define MathPad_YYParse_h + +extern MPParsedElement *parseResult; + +int yyparse(); + +#endif diff --git a/MathPad/MPMath.lm b/MathPad/MPMath.lm new file mode 100644 index 0000000..10c8827 --- /dev/null +++ b/MathPad/MPMath.lm @@ -0,0 +1,16 @@ +%option noyywrap +%{ + @import Foundation; + #include "MPMath.tab.h" +%} +%% + /* Ignore Whitespaces */ +[ \t\n] ; + /* Operators. Divisions are automatically transformed into fractions and dealt + with elsewhere. */ +\+ { return PLUS; } +- { return MINUS; } +\* { return DOT; } + /* Numbers */ +[0-9]+(\.[0-9]+)? { yylval.number = atof(yytext); return NUMBER; } +%% \ No newline at end of file diff --git a/MathPad/MPMath.ym b/MathPad/MPMath.ym new file mode 100644 index 0000000..b09ae8f --- /dev/null +++ b/MathPad/MPMath.ym @@ -0,0 +1,126 @@ +%{ + #import "MPMath.h" + #define AT @ + + MPParsedElement *parseResult; + + int yylex(); + int yyparse(); + FILE *yyin; + + void yyerror(const char *s); +%} + +%error-verbose + +%initial-action +{ + parseResult = [[MPParsedElement alloc] init]; +}; + +%union { + double number; +} + /* Terminals */ +%token PLUS +%left MINUS +%token DOT +%token NUMBER + + /* Nonterminals */ +%type summands +%type factor +%type product + +%% + +element: + factor { parseResult.isFactor = YES; + parseResult.factor = $1; + } + | operator + | prefix summands suffix + ; + +factor: + DOT product DOT { $$ = $2; + } + | DOT product { $$ = $2; + } + | product DOT { $$ = $1; + } + | product { $$ = $1; + } + ; + +product: + product DOT product { $$ = $1 * $3; + } + | product product { $$ = $1 * $2; + } + | NUMBER { $$ = $1; + } + ; + +operator: + PLUS { parseResult.suffixMultiplicator = 1; + parseResult.hasSuffixMultiplicator = YES; + } + | MINUS { parseResult.suffixMultiplicator = -1; + parseResult.hasSuffixMultiplicator = YES; + NSLog(AT"Op"); + } + | DOT { parseResult.isFactor = YES; + parseResult.factor = 1; + } + | { parseResult.isFactor = YES; + parseResult.factor = 1; + } + ; + +prefix: + DOT product { parseResult.prefixMultiplicator = $2; + parseResult.hasPrefixMultiplicator = YES; + parseResult.prefixOperatorExplicit = YES; + } + | product { parseResult.prefixMultiplicator = $1; + parseResult.hasPrefixMultiplicator = YES; + parseResult.prefixOperatorExplicit = YES; + } + | { parseResult.hasPrefixMultiplicator = NO; + } + ; + +summands: + summands summand + | summand + ; + +summand: + PLUS product { [parseResult.summands addObject:AT($2)]; + } + | MINUS product { [parseResult.summands addObject:AT(-$2)]; + } + ; + +suffix: + PLUS { parseResult.suffixMultiplicator = 1; + parseResult.hasSuffixMultiplicator = YES; + } + | MINUS { parseResult.suffixMultiplicator = -1; + parseResult.hasSuffixMultiplicator = YES; + } + | DOT { parseResult.suffixMultiplicator = 0; + parseResult.hasSuffixMultiplicator = YES; + } + | { parseResult.hasSuffixMultiplicator = NO; + } + ; + +%% + +void yyerror(const char *s) { + NSLog(@"EEK, parse error! Message: %s", s); + // might as well halt now: + exit(-1); +} \ No newline at end of file diff --git a/MathPad/MPParsedElement.h b/MathPad/MPParsedElement.h new file mode 100644 index 0000000..3463b6c --- /dev/null +++ b/MathPad/MPParsedElement.h @@ -0,0 +1,39 @@ +// +// MPParsedElement.h +// MathPad +// +// Created by Kim Wittenburg on 05.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import + +// DEBUG STUFF +// Simple Operator: +/-/* +// Simple Factor: * 5.4 * / * 5,4 / 5,4 * / 5,4 +// Independant Math: -1+2-3 + +@interface MPParsedElement : NSObject + +@property (nonatomic) BOOL isFactor; +@property (nonatomic) double factor; + +@property (nonatomic, strong) NSMutableArray *summands; + +@property (nonatomic) double prefixMultiplicator; +@property (nonatomic) BOOL hasPrefixMultiplicator; +@property (nonatomic, getter = isPrefixOperatorExplicit) BOOL prefixOperatorExplicit; +@property (nonatomic) double suffixMultiplicator; +@property (nonatomic) BOOL hasSuffixMultiplicator; + +// No error checking done. The string parsed may for example end with an operator +- (double)valueAtBeginning; +- (double)valueAtEnd; +- (double)standaloneValue; + +// For error checking +- (BOOL)isValidElementAtBeginning; +- (BOOL)isValidElementInBetween; +- (BOOL)isValidElementAtEnd; + +@end diff --git a/MathPad/MPParsedElement.m b/MathPad/MPParsedElement.m new file mode 100644 index 0000000..9c61dec --- /dev/null +++ b/MathPad/MPParsedElement.m @@ -0,0 +1,60 @@ +// +// MPParsedElement.m +// MathPad +// +// Created by Kim Wittenburg on 05.09.14. +// Copyright (c) 2014 Kim Wittenburg. All rights reserved. +// + +#import "MPParsedElement.h" + +@implementation MPParsedElement + +- (instancetype)init +{ + self = [super init]; + if (self) { + _summands = [[NSMutableArray alloc] init]; + } + return self; +} + +- (double)standaloneValue +{ + if (self.isFactor) { + return self.factor; + } + return self.prefixMultiplicator + [[self.summands valueForKeyPath:@"@sum.self"] doubleValue]; +} + +- (BOOL)isValidElementAtBeginning +{ + return NO; +} + +- (BOOL)isValidElementInBetween +{ + return YES; +} + +- (BOOL)isValidElementAtEnd +{ + return NO; +} + +#pragma mark NSCopying +- (id)copyWithZone:(NSZone *)zone +{ + MPParsedElement *copy = [[MPParsedElement allocWithZone:zone] init]; + copy.isFactor = self.isFactor; + copy.factor = self.factor; + copy.summands = self.summands.mutableCopy; + copy.prefixMultiplicator = self.prefixMultiplicator; + copy.hasPrefixMultiplicator = self.hasPrefixMultiplicator; + copy.prefixOperatorExplicit = self.prefixOperatorExplicit; + copy.suffixMultiplicator = self.suffixMultiplicator; + copy.hasSuffixMultiplicator = self.hasSuffixMultiplicator; + return copy; +} + +@end