Started to Implement the Parser
This commit is contained in:
34
MathPad/MPArrayCache.h
Normal file
34
MathPad/MPArrayCache.h
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// MPArrayCache.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 31.08.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// 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
|
||||
59
MathPad/MPArrayCache.m
Normal file
59
MathPad/MPArrayCache.m
Normal file
@@ -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
|
||||
30
MathPad/MPExpressionEvaluator.h
Normal file
30
MathPad/MPExpressionEvaluator.h
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// MPExpressionEvaluator.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 31.08.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#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
|
||||
56
MathPad/MPExpressionEvaluator.m
Normal file
56
MathPad/MPExpressionEvaluator.m
Normal file
@@ -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
|
||||
20
MathPad/MPMath.h
Normal file
20
MathPad/MPMath.h
Normal file
@@ -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
|
||||
16
MathPad/MPMath.lm
Normal file
16
MathPad/MPMath.lm
Normal file
@@ -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; }
|
||||
%%
|
||||
126
MathPad/MPMath.ym
Normal file
126
MathPad/MPMath.ym
Normal file
@@ -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> NUMBER
|
||||
|
||||
/* Nonterminals */
|
||||
%type <number> summands
|
||||
%type <number> factor
|
||||
%type <number> 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);
|
||||
}
|
||||
39
MathPad/MPParsedElement.h
Normal file
39
MathPad/MPParsedElement.h
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// MPParsedElement.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 05.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// DEBUG STUFF
|
||||
// Simple Operator: +/-/*
|
||||
// Simple Factor: * 5.4 * / * 5,4 / 5,4 * / 5,4
|
||||
// Independant Math: -1+2-3
|
||||
|
||||
@interface MPParsedElement : NSObject <NSCopying>
|
||||
|
||||
@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
|
||||
60
MathPad/MPParsedElement.m
Normal file
60
MathPad/MPParsedElement.m
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user