summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOskari Timperi <oskari.timperi@iki.fi>2015-12-08 21:38:50 +0200
committerOskari Timperi <oskari.timperi@iki.fi>2015-12-08 21:38:50 +0200
commitd6d401c83f186e72a105821e60a856ca4d5c998c (patch)
tree55e19022be522c3616ef2ffef2244c2a8fbbf6b8
downloadlbasi-d6d401c83f186e72a105821e60a856ca4d5c998c.tar.gz
lbasi-d6d401c83f186e72a105821e60a856ca4d5c998c.zip
part 1 + tests
-rw-r--r--.gitattributes3
-rw-r--r--Makefile7
-rw-r--r--calc1.pas219
-rw-r--r--tests/calc1.txt26
4 files changed, 255 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..de3c41b
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,3 @@
+* text=auto
+*.pas text
+*.txt text
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..888575f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,7 @@
+FPC_FLAGS = -Mobjfpc -FUobj -g
+
+calc1: calc1.pas | obj
+ fpc ${FPC_FLAGS} $<
+
+obj:
+ mkdir obj
diff --git a/calc1.pas b/calc1.pas
new file mode 100644
index 0000000..0757421
--- /dev/null
+++ b/calc1.pas
@@ -0,0 +1,219 @@
+program calc1;
+
+{$H+}
+
+uses
+ typinfo, sysutils, character;
+
+type
+ TokenType = (TT_Integer, TT_Plus, TT_Minus, TT_Eof);
+
+ Token = class
+ TokenType: TokenType;
+ constructor Create(Type_: TokenType);
+ function ToStr: String; virtual;
+ end;
+
+ TokenInteger = class(Token)
+ Val: Integer;
+ constructor Create(Value_: Integer);
+ function ToStr: String; override;
+ end;
+
+ TokenPlus = class(Token)
+ constructor Create;
+ end;
+
+ TokenMinus = class(Token)
+ constructor Create;
+ end;
+
+ TokenEof = class(Token)
+ constructor Create;
+ end;
+
+ Interpreter = class
+ Text: AnsiString;
+ CurPos: Integer;
+ Current: Token;
+
+ constructor Create(Text_: AnsiString);
+
+ procedure Error;
+ function GetNextToken: Token;
+ procedure Eat(T: TokenType);
+ function Expr: Integer;
+ end;
+
+constructor Token.Create(Type_: TokenType);
+begin
+ inherited Create;
+ TokenType := Type_;
+end;
+
+function Token.ToStr: String;
+begin
+ Result := GetEnumName(TypeInfo(TokenType), Ord(Self.TokenType));
+end;
+
+constructor TokenInteger.Create(Value_: Integer);
+begin
+ inherited Create(TT_Integer);
+ Val := Value_;
+end;
+
+function TokenInteger.ToStr: String;
+begin
+ Result := inherited;
+ Result := Result + '(' + IntToStr(Val) + ')';
+end;
+
+constructor TokenPlus.Create;
+begin
+ inherited Create(TT_Plus);
+end;
+
+constructor TokenMinus.Create;
+begin
+ inherited Create(TT_Minus);
+end;
+
+
+constructor TokenEof.Create;
+begin
+ inherited Create(TT_Eof);
+end;
+
+constructor Interpreter.Create(Text_: String);
+begin
+ inherited Create;
+ Text := Text_;
+ CurPos := 1;
+ Current := Default(Token);
+end;
+
+procedure Interpreter.Error;
+begin
+ Raise Exception.Create('error!');
+end;
+
+function Interpreter.GetNextToken: Token;
+var
+ Text_: String;
+ CurrentChar: Char;
+ Start: Integer;
+
+ procedure SkipWhitespace;
+ begin
+ while (CurPos <= Length(Text)) and IsWhiteSpace(Text[CurPos]) do
+ Inc(CurPos);
+ end;
+
+ function AtEnd: Boolean;
+ begin
+ Result := CurPos > Length(Text);
+ end;
+begin
+ SkipWhitespace;
+
+ if AtEnd then
+ begin
+ Result := TokenEof.Create;
+ Exit;
+ end;
+
+ Start := CurPos;
+
+ while (CurPos <= Length(Text)) and IsDigit(Text[CurPos]) do
+ Inc(CurPos);
+
+ if CurPos - Start > 0 then
+ begin
+ Result := TokenInteger.Create(StrToInt(Copy(Text, Start,
+ CurPos-Start)));
+ Exit;
+ end;
+
+ CurrentChar := Text[CurPos];
+
+ if CurrentChar = '+' then
+ begin
+ Result := TokenPlus.Create;
+ Inc(CurPos);
+ Exit;
+ end
+ else if CurrentChar = '-' then
+ begin
+ Result := TokenMinus.Create;
+ Inc(CurPos);
+ Exit;
+ end;
+
+ Error;
+end;
+
+procedure Interpreter.Eat(T: TokenType);
+begin
+ if Current.TokenType = T then
+ begin
+ Current := GetNextToken;
+ end
+ else
+ Error;
+end;
+
+function Interpreter.Expr: Integer;
+var
+ Left, Op, Right: Token;
+begin
+ Current := GetNextToken;
+
+ Left := Current;
+ Eat(TT_Integer);
+
+ Op := Current;
+ Eat(TT_Minus);
+
+ Right := Current;
+ Eat(TT_Integer);
+
+ Result := TokenInteger(Left).Val - TokenInteger(Right).Val;
+end;
+
+var
+ Interp: Interpreter;
+ Line: String;
+ I: Integer;
+
+procedure InterpString(S: String);
+begin
+ Interp := Interpreter.Create(S);
+ WriteLn(Interp.Expr);
+ FreeAndNil(Interp);
+end;
+
+procedure InputLoop;
+begin
+ while True do
+ begin
+ Write('calc> ');
+ if Eof(Input) then break;
+ ReadLn(Line);
+ if Length(Line) = 0 then continue;
+ InterpString(Line);
+ end;
+end;
+
+begin
+ if ParamCount > 0 then
+ begin
+ Line := '';
+ for I := 1 to ParamCount do
+ begin
+ Line := Line + ParamStr(I);
+ end;
+ InterpString(Line);
+ end
+ else
+ InputLoop;
+end.
diff --git a/tests/calc1.txt b/tests/calc1.txt
new file mode 100644
index 0000000..a343306
--- /dev/null
+++ b/tests/calc1.txt
@@ -0,0 +1,26 @@
+*** Settings ***
+Library Process
+
+*** Keywords ***
+Run Calculator
+ [Arguments] ${expr}
+ ${result} = Run Process ${CURDIR}/../calc1 ${expr}
+ [Return] ${result}
+
+Calculate
+ [Arguments] ${expr}
+ ${rc} = Run Calculator ${expr}
+ Should Be Equal As Integers ${rc.rc} 0
+ ${result} = Get Variable Value ${rc.stdout}
+ [Return] ${result}
+
+The result of ${calculation} should be ${expected}
+ ${result} = Calculate ${calculation}
+ Should Be Equal As Integers ${expected} ${result}
+
+*** Test Cases ***
+Simple calculations
+ [Template] The result of ${calculations} should be ${expected}
+ 1-1 0
+ 100-3 97
+ 50${SPACE*5}- 5 45