Archived
1

Started to Implement the Parser

This commit is contained in:
Kim Wittenburg
2014-09-06 01:54:15 +02:00
parent 6aafbf9d2e
commit 8df8317413
10 changed files with 570 additions and 16 deletions

34
MathPad/MPArrayCache.h Normal file
View 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
View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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