Oxygene for Java version of Arithmetic
Arithmetic using Reverse Polish Notation (RPN)
Introduction
You will see that much of the code remains in its original form. We draw your attention to the following points regarding the conversion from pure Pascal to Oxygene for Java.
- Arrays are changed to be zero-based to be accepted (even though the value with index zero might not be used).
- Individual characters in a string are zero-based.
- System.out.Printf is used for formatting real numbers.
- The assignment Result := ... instead of stackPop := ... must be used for the return value of function stackPop.
- "Float" is used instead of "Real" in Oxygene for Java.
At the command prompt we typed (1) cd C:\Oxygen to change directory to the program folder, (2) msbuild arithmetic.oxygene to compile to byte-code in arithmetic.jar then (3) java -jar bin\Release\arithmetic.jar to execute the program. You can open the project file in Visual Studio and execute the program with a click on the green triangle.
The program (arithmetic.pas)
namespace arithmetic; { Copyright (c) 2011 Peter Hearnshaw Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License, as described at http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/ Converted to Oxygene for Java by PPS. } interface var inputStr : string; inputChars : array[0 .. 255] of SByte; inputStrWithSpaces : string; ExpressionArray : array[0 .. 80] of string; ExpressionArrayIsOperator, //parallel to ExpressionArray, stating whether num or op VariablisedExpressionArray, RPNVariablisedExpressionArray: array[0 .. 80] of SByte; ExpressionArrayLength : Integer; VariableStorageArray : array[0 .. 34] of real; i, RPNcount : Integer; isOperator : boolean := false; currentChar : char; tempString : string; numOfVariables : integer := 0; Popped, Scanned, CurrentChrByte : SByte; finalAnswer, tempReal1, tempReal2 : real; myRealStack : array[0 .. 100] of real; indexOfTopOfStack : integer := -1; implementation method stackPush(value : real); begin inc(indexOfTopOfStack); myRealStack[indexOfTopOfStack] := value; end; method stackPop : real; begin Result := myRealStack[indexOfTopOfStack]; //Use "Result" not name of method dec(indexOfTopOfStack); end; begin for i := 0 to 80 do begin ExpressionArray[i] := ''; end; writeln('Please input an expression (with no spaces): '); System.in.read(inputChars); inputStrWithSpaces := new String(inputChars); inputStr := inputStrWithSpaces.trim; //inputStr := '(1+2.5*(2.762+53.1*(2+-5*-4*(2+3)))+-61.7)'; writeln('Expression: ' + inputStr); //PROCESS INITIAL EXPRESSION expressionArrayLength := 0; currentChar := inputStr[0]; if (ord(currentChar) > 47) then expressionArrayLength := 1; //expressionArrayLength becomes one if //first char is a number because numbers will be added to the end of the //current array position for i := 0 to length(inputStr) - 1 do begin currentChar := inputStr[i]; //if current char is - and last char was an operator other than ) if (ord(currentChar) = 45) and (isOperator = true) and (ord(inputStr[i - 1]) <> 41) then begin isOperator := false; inc(expressionArrayLength); ExpressionArrayIsOperator[expressionArrayLength] := 0; end else begin if (ord(currentChar) < 48) and (ord(currentChar) <> 46) then begin isOperator := true; inc(expressionArrayLength); ExpressionArrayIsOperator[expressionArrayLength] := 1; end; if (ord(currentChar) > 47) and (isOperator = true) then begin isOperator := false; inc(expressionArrayLength); ExpressionArrayIsOperator[expressionArrayLength] := 0; end; end; ExpressionArray[expressionArrayLength] := ExpressionArray[expressionArrayLength] + currentChar; end; //VARIABLISE EXPRESSION //by variablising I mean turning 41 + 21 into a + b, 'a' stored in array as //41 and 'b' as 21 numOfVariables := 0; for i := 1 to expressionArrayLength do begin if (ExpressionArrayIsOperator[i] = 0) then //i.e. is a number begin inc(numOfVariables); tempString := ExpressionArray[i]; VariableStorageArray[numOfVariables] := new Float(tempString); VariablisedExpressionArray[i] := 96 + numOfVariables; //first //variable will be 'a' then 'b'... end; if (ExpressionArrayIsOperator[i] = 1) then //i.e. is an operator begin tempString := ExpressionArray[i]; VariablisedExpressionArray[i] := ord(tempString[0]); end; end; //PRINT OUT System.out.print('Expression In Variables: '); for i := 1 to expressionArrayLength do begin System.out.print(chr(VariablisedExpressionArray[i])); if (i <> expressionArrayLength) then System.out.print(','); end; writeln; writeln('Variables:'); for i := 1 to numOfVariables do begin System.out.print(' '+ chr(96 + i) +' = '); System.out.printf('%.3f', VariableStorageArray[i]); writeln; end; finalAnswer := 0; //CONVERT TO REVERSE POLISH NOTATION indexOfTopOfStack := 0; RPNcount := 0; for i := 1 to expressionArrayLength do begin if VariablisedExpressionArray[i] > 47 then //is a number begin inc(RPNcount); RPNVariablisedExpressionArray[RPNcount] := VariablisedExpressionArray[i]; end; if VariablisedExpressionArray[i] < 48 then //is an operator begin //Don't bother at all with this if there isn't anything on the stack if (indexOfTopOfStack <> 0) and (VariablisedExpressionArray[i] <> 40) and (VariablisedExpressionArray[i] <> 41) then begin repeat popped := Math.Round(stackPop); stackPush(popped); if popped = 40 then begin scanned := 100; //This makes sure the program will escape //the repeat, to immediately push the operator end else begin //poppedItem := popped; if (popped = 42) or (popped = 47) then // * or / begin popped := 2; //priority 2 end else begin popped := 1; //priority 1 end; scanned := VariablisedExpressionArray[i]; if (scanned = 42) or (scanned = 47) then begin scanned := 2; //priority 2 end else begin scanned := 1; //priority 1 end; if (scanned <= popped) then // Pop the stack to the end of the RPN array begin inc(RPNcount); popped := Math.Round(stackPop); RPNVariablisedExpressionArray[RPNcount] := popped; end; end; until (scanned > popped) or (indexOfTopOfStack = 0); end; stackPush(VariablisedExpressionArray[i]); //VERY important if (VariablisedExpressionArray[i] = 41) then begin stackPop; //just to get off the ) we just added popped := Math.Round(stackPop); expressionArrayLength := expressionArrayLength - 2; {This takes two away from the current expression array length because two brackets have been removed from the array. Pop the operators within the brackets to the end of the RPN array.} while popped <> 40 do begin inc(RPNcount); RPNVariablisedExpressionArray[RPNcount] := popped; popped := Math.Round(stackPop); end; end; end; end; //Pop any remaining operators on the stack to the RPN array if indexOfTopOfStack > 0 then begin for i := 0 to indexOfTopOfStack - 1 do begin inc(RPNcount); popped := Math.Round(stackPop); RPNVariablisedExpressionArray[RPNcount] := popped; end; end; System.out.print('In Reverse Polish Notation: '); for i := 1 to expressionArrayLength do begin System.out.print(chr(RPNVariablisedExpressionArray[i])); end; writeln; {Evaluate the RPN. Before the operators are used, the stack will contain numbers pushed with the line of code in the else clause below: stackPush(VariableStorageArray[currentChrByte - 96]);} indexOfTopOfStack := 0; for i:= 1 to expressionArrayLength do begin currentChrByte := RPNVariablisedExpressionArray[i]; case currentChrByte of 43 : begin tempReal1 := stackPop; tempReal2 := stackPop; stackPush(tempReal1 + tempReal2); end; 42 : begin tempReal1 := stackPop; tempReal2 := stackPop; tempReal2 := tempReal2 * tempReal1; stackPush(tempReal2); end; 45 : begin tempReal1 := stackPop; tempReal2 := stackPop; stackPush(tempReal2 - tempReal1); end; 47 : begin tempReal1 := stackPop; tempReal2 := stackPop; tempReal2 := tempReal2 / tempReal1; stackPush(tempReal2); end; else begin //Push the number represented by its lower case letter to the stack stackPush(VariableStorageArray[currentChrByte - 96]); end; end; end; finalAnswer := stackPop; System.out.printf('Final Answer: %.3f', finalAnswer ); System.in.read; end.
The project file (arithmetic.oxygene)
<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> <PropertyGroup> <ProductVersion>3.5</ProductVersion> <OutputType>Exe</OutputType> <Configuration Condition="'$(Configuration)' == ''">Release</Configuration> <Name>Arithmetic</Name> <RootNamespace>org.me.arithmetic</RootNamespace> <AssemblyName>arithmetic</AssemblyName> <StartupClass /> <DefaultUses /> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <Optimize>true</Optimize> <OutputPath>.\bin\Release</OutputPath> <GenerateDebugInfo>False</GenerateDebugInfo> <GenerateMDB>False</GenerateMDB> <EnableAsserts>False</EnableAsserts> <TreatWarningsAsErrors>False</TreatWarningsAsErrors> <CaptureConsoleOutput>False</CaptureConsoleOutput> <StartMode>Project</StartMode> <RegisterForComInterop>False</RegisterForComInterop> <CpuType>anycpu</CpuType> <RuntimeVersion>v25</RuntimeVersion> <XmlDoc>False</XmlDoc> <XmlDocWarningLevel>WarningOnPublicMembers</XmlDocWarningLevel> <EnableUnmanagedDebugging>False</EnableUnmanagedDebugging> </PropertyGroup> <ItemGroup> <Reference Include="rt.jar" /> </ItemGroup> <ItemGroup> <Folder Include="Properties\" /> </ItemGroup> <ItemGroup> <Compile Include="arithmetic.pas"> <SubType>Code</SubType> </Compile> </ItemGroup> <Import Project="$(MSBuildExtensionsPath)\RemObjects Software\Oxygene\RemObjects.Oxygene.Cooper.targets" /> </Project>