// Programmer's RPN Calculator
// Karl L. Barrus <karl at klbarrus dot com>
// July 2, 1996
//
// Copyright (c) 1996 Karl L. Barrus
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 675 Mass Ave, Cambridge, MA 02139, USA.
import java.awt.*;
public class ProgCalc extends java.applet.Applet
{
LCDDisplay display;
CalcKeyboard keyboard;
long lcdValue[];
TextField lcdDisplay[];
Component calcKeys[];
int radix;
CheckboxGroup radixMode;
int inputMode;
final int numLines = 4;
public boolean action( Event event, Object arg )
{
if ( event.target instanceof Button )
{
String key = ( String ) arg;
if ( key.equals( "-> K" ) || key.equals( "-> M" ) || key.equals( "K ->" ) || key.equals( "M ->" ) )
DoConvert( key );
else if ( key.equals( "AND" ) || key.equals( "OR" ) || key.equals( "NOT" ) || key.equals( "XOR" ) )
DoLogicalOp( key );
else if ( key.equals( "enter" ) || key.equals( "drop" ) || key.equals( "swap" ) )
DoStackAction( key );
else if ( key.equals( "+" ) || key.equals( "-" ) || key.equals( "*" ) || key.equals( "/" ) || key.equals( "^" ) )
DoMathOp( key );
else
DoInput( key );
UpdateLCDDisplay();
return true;
}
else if ( event.target instanceof Checkbox )
{
DoDisplayModeChange( radixMode.getCurrent().getLabel() );
UpdateLCDDisplay();
return true;
}
else
{
return false;
}
}
void DoConvert( String key )
{
long in = Long.parseLong( lcdDisplay[ 0 ].getText(), radix );
if ( key.equals( "-> K" ) )
lcdValue[ 0 ] = in / 1024;
else if ( key.equals( "-> M" ) )
lcdValue[ 0 ] = in / 1024 / 1024;
else if ( key.equals( "K ->" ) )
lcdValue[ 0 ] = in * 1024;
else if ( key.equals( "M ->" ) )
lcdValue[ 0 ] = in * 1024 * 1024;
inputMode = 0;
}
void DoDisplayModeChange( String key )
{
lcdValue[ 0 ] = Long.parseLong( lcdDisplay[ 0 ].getText(), radix );
if ( key.equals( "HEX" ) )
SetBase( 16 );
else if ( key.equals( "DEC" ) )
SetBase( 10 );
else if ( key.equals( "OCT" ) )
SetBase( 8 );
else if ( key.equals( "BIN" ) )
SetBase( 2 );
inputMode = 0;
}
void DoInput( String key )
{
if ( inputMode == 0 )
{
inputMode = 1;
PushStack( key );
}
else
{
long keyval = Long.parseLong( key, radix );
if ( ( Long.MAX_VALUE - keyval ) / radix >= lcdValue[ 0 ] )
lcdValue[ 0 ] = lcdValue[ 0 ] * radix + Long.parseLong( key, radix );
}
}
void DoLogicalOp( String key )
{
if ( key.equals( "NOT" ) )
{
long arg1 = Long.parseLong( lcdDisplay[ 0 ].getText(), radix );
lcdValue[ 0 ] = ~arg1;
}
else
{
long arg1 = lcdValue[ 1 ];
long arg2 = Long.parseLong( lcdDisplay[ 0 ].getText(), radix );
long result = 0;
if ( key.equals( "AND" ) )
result = arg1 & arg2;
else if ( key.equals( "OR" ) )
result = arg1 | arg2;
else if ( key.equals( "XOR" ) )
result = arg1 ^ arg2;
PopStack( result );
}
inputMode = 0;
}
void DoMathOp( String key )
{
long arg1 = lcdValue[ 1 ];
long arg2 = Long.parseLong( lcdDisplay[ 0 ].getText(), radix );
long result = 0;
if ( key.equals( "+" ) )
result = arg1 + arg2;
else if ( key.equals( "-" ) )
result = arg1 - arg2;
else if ( key.equals( "*" ) )
result = arg1 * arg2;
else if ( key.equals( "/" ) )
{
try
{
result = arg1 / arg2;
}
catch ( ArithmeticException ae )
{
result = 0;
}
}
else if ( key.equals( "^" ) )
{
try
{
result = ( long ) Math.pow( ( double ) arg1, ( double ) arg2 );
}
catch ( ArithmeticException ae )
{
result = 0;
}
}
PopStack( result );
inputMode = 0;
}
void DoStackAction( String key )
{
if ( key.equals( "enter" ) )
{
if ( inputMode == 1 )
{
inputMode = 0;
}
else
{
PushStack( lcdDisplay[ 0 ].getText() );
}
}
else if ( key.equals( "drop" ) )
{
PopStack( lcdValue[ 1 ] );
}
else if ( key.equals( "swap" ) )
{
long temp = Long.parseLong( lcdDisplay[ 0 ].getText(), radix );
lcdValue[ 0 ] = lcdValue[ 1 ];
lcdValue[ 1 ] = temp;
}
inputMode = 0;
}
public void init()
{
setLayout( new GridLayout( 2, 1 ) );
display = new LCDDisplay( this );
keyboard = new CalcKeyboard( this );
inputMode = 0;
SetBase( 10 );
add( display );
add( keyboard );
}
public boolean keyDown( Event event, int key )
{
boolean handled = false;
switch( key )
{
case 42:
DoMathOp( "*" );
handled = true;
break;
case 43:
DoMathOp( "+" );
handled = true;
break;
case 45:
DoMathOp( "-" );
handled = true;
break;
case 47:
DoMathOp( "/" );
handled = true;
break;
case 94:
DoMathOp( "^" );
handled = true;
break;
case 10:
DoStackAction( "enter" );
handled = true;
break;
case 48:
case 49:
DoInput( String.valueOf( key - 48 ) );
handled = true;
break;
case 50:
case 51:
case 52:
case 53:
case 54:
case 55:
if ( radix >= 8 )
{
DoInput( String.valueOf( key - 48 ) );
handled = true;
}
break;
case 56:
case 57:
if ( radix >= 10 )
{
DoInput( String.valueOf( key - 48 ) );
handled = true;
}
break;
case 65:
case 66:
case 67:
case 68:
case 69:
case 70:
case 97:
case 98:
case 99:
case 100:
case 101:
case 102:
if ( radix >= 16 )
{
DoInput( String.valueOf( ( char ) key ) );
handled = true;
}
break;
};
UpdateLCDDisplay();
return handled;
}
void PopStack( long result )
{
lcdValue[ 0 ] = result;
for ( int i = 1; i <= numLines - 2; i++ )
lcdValue[ i ] = lcdValue[ i + 1 ];
lcdValue[ numLines - 1 ] = 0;
}
void PushStack( String value )
{
for ( int i = numLines - 1; i > 0; i-- )
lcdValue[ i ] = lcdValue[ i - 1 ];
lcdValue[ 0 ] = Long.parseLong( value, radix );
}
void SetBase( int base )
{
radix = base;
int[] keyIndex =
{
32, 26, 27, 28, 20, 21, 22, 14, 15, 16, 8, 9, 10, 2, 3, 4
};
switch( base )
{
case 2:
calcKeys[ keyIndex[ 2 ] ].disable();
calcKeys[ keyIndex[ 3 ] ].disable();
calcKeys[ keyIndex[ 4 ] ].disable();
calcKeys[ keyIndex[ 5 ] ].disable();
calcKeys[ keyIndex[ 6 ] ].disable();
calcKeys[ keyIndex[ 7 ] ].disable();
// fall through
case 8:
calcKeys[ keyIndex[ 8 ] ].disable();
calcKeys[ keyIndex[ 9 ] ].disable();
// fall through
case 10:
calcKeys[ keyIndex[ 10 ] ].disable();
calcKeys[ keyIndex[ 11 ] ].disable();
calcKeys[ keyIndex[ 12 ] ].disable();
calcKeys[ keyIndex[ 13 ] ].disable();
calcKeys[ keyIndex[ 14 ] ].disable();
calcKeys[ keyIndex[ 15 ] ].disable();
}
switch( base )
{
case 16:
calcKeys[ keyIndex[ 15 ] ].enable();
calcKeys[ keyIndex[ 14 ] ].enable();
calcKeys[ keyIndex[ 13 ] ].enable();
calcKeys[ keyIndex[ 12 ] ].enable();
calcKeys[ keyIndex[ 11 ] ].enable();
calcKeys[ keyIndex[ 10 ] ].enable();
// fall through
case 10:
calcKeys[ keyIndex[ 9 ] ].enable();
calcKeys[ keyIndex[ 8 ] ].enable();
// fall through
case 8:
calcKeys[ keyIndex[ 7 ] ].enable();
calcKeys[ keyIndex[ 6 ] ].enable();
calcKeys[ keyIndex[ 5 ] ].enable();
calcKeys[ keyIndex[ 4 ] ].enable();
calcKeys[ keyIndex[ 3 ] ].enable();
calcKeys[ keyIndex[ 2 ] ].enable();
// fall through
case 2:
calcKeys[ keyIndex[ 1 ] ].enable();
calcKeys[ keyIndex[ 0 ] ].enable();
}
}
void UpdateLCDDisplay()
{
for ( int i = 0; i < numLines; i++ )
lcdDisplay[ i ].setText( Long.toString( lcdValue[ i ], radix ) );
}
}
class LCDDisplay extends Panel
{
ProgCalc app;
LCDDisplay( ProgCalc target )
{
app = target;
setLayout( new GridLayout( app.numLines, 1 ) );
app.lcdValue = new long[ app.numLines ];
app.lcdDisplay = new TextField[ app.numLines ];
for ( int i = app.numLines - 1; i >= 0; i-- )
{
app.lcdValue[ i ] = 0;
app.lcdDisplay[ i ] = new TextField( String.valueOf( app.lcdValue[ i ] ), 64 );
app.lcdDisplay[ i ].setEditable( false );
add( app.lcdDisplay[ i ] );
}
}
}
class CalcKeyboard extends Panel
{
ProgCalc app;
String[] keyLabels =
{
"HEX", "AND", "D", "E", "F", "+",
"DEC", "OR", "A", "B", "C", "-",
"OCT", "NOT", "7", "8", "9", "*",
"BIN", "XOR", "4", "5", "6", "/",
"-> K", "K ->", "1", "2", "3", "^",
"-> M", "M ->", "0", "drop", "swap", "enter"
};
CalcKeyboard( ProgCalc target )
{
app = target;
setLayout( new GridLayout( 6, 6, 2, 2 ) );
app.calcKeys = new Component[ 36 ];
app.radixMode = new CheckboxGroup();
for ( int i = 0; i < 36; i++ )
{
if ( i == 0 || i == 6 || i == 12 || i == 18 )
app.calcKeys[ i ] = ( Component ) new Checkbox( keyLabels[ i ], app.radixMode, false );
else
app.calcKeys[ i ] = ( Component ) new Button( keyLabels[ i ] );
app.radixMode.setCurrent( ( Checkbox ) app.calcKeys[ 6 ] );
add( app.calcKeys[ i ] );
}
}
}