home *** CD-ROM | disk | FTP | other *** search
- (*********************************************************************
- * *** 電卓 *** *
- * *
- * HAPPyのサンプルプログラム *
- * (作者 浅野比富美 Public Domain Software) *
- *********************************************************************)
-
- program calculator(input,output) ;
-
- label 1 ;
-
- const SYNe = '式が誤っている ' ;
- DIVe = '0で割ろうとしている ' ;
-
- LimitInt = 99999999 ; { 整数演算の最大値 }
-
- type kindType = (int,rea) ; { 整数 実数 }
- valueType = record { 演算結果 の 型 }
- kind : kindType ; { 結果の型 }
- vi : integer ; { 整数の値 }
- vr : real { 実数の値 }
- end ;
- string20 = packed array[1..20] of char ; { エラーメッセージの型 }
-
- var ch : char ; { 読んだ文字 }
- val,oldVal : valueType ; { 演算結果 }
-
- (****************************)
- (* エラーメッセージ出力処理 *)
- (****************************)
- procedure error(message : string20) ;
- begin
- writeln(message) ;
- readln ; { 以降改行までの入力を無視する }
- goto 1 { 次の式の処理(メイン処理)へ }
- end ;
-
- (****************************)
- (* 実数変換処理 *)
- (****************************)
- procedure cnvFloat(var val : valueType; r : real) ;
- begin
- val.kind := rea ;
- val.vr := r
- end ;
-
- (****************************)
- (* 数の入力処理 *)
- (****************************)
- procedure inputNumber(var val : valueType) ;
- label 8 ;
- var p : real ;
- sign : char ;
- begin
- with val do
- begin
- kind := int ; { とりあえず整数としておく }
- vi := 0 ;
-
- if (ch = '+') or (ch ='-') then { 符号がある時 }
- begin
- sign := ch ; { 符号を記憶しておく }
- read(ch)
- end
- else sign := ' ' ;
-
- if (ch = 'x') or (ch = 'X') then { 前回の答え数値の指示の時 }
- begin
- val := oldVal ; { 前回の答えを 値 とする }
- read(ch) ;
- goto 8 { 符号の処理へ }
- end ;
-
- if ('0' <= ch) and (ch <= '9') then
- begin
- vi := ord(ch) - ord('0') ;
- read(ch) ;
- while ('0' <= ch) and (ch <= '9') do
- begin
- if kind = int then
- begin
- vi := 10 * vi + (ord(ch)-ord('0')) ;
- if vi > LimitInt then { 整数オーバーフローしている時 }
- cnvFloat(val,vi) { 以降の演算は実数で行う }
- end
- else vr := 10 * vr + (ord(ch)-ord('0')) ;
- read(ch)
- end ;
- if ch = '.' then { 小数点がある時 }
- begin
- cnvFloat(val,vi) ; { 以降の演算は実数で行う }
- p := 0.1 ;
- read(ch) ;
- if ('0' <= ch) and (ch <= '9') then
- repeat
- vr := vr + p * (ord(ch)-ord('0')) ;
- p := 0.1 * p ;
- read(ch)
- until ('0' > ch) or (ch > '9')
- else error(SYNe)
- end
- end
- else error(SYNe) ;
-
- 8: if sign = '-' then { 負の符号の時 }
- if kind = int then vi := -vi { 値を反転する }
- else vr := -vr
- end {with val}
- end ;
-
- (******************************)
- (* オーバーフローチェック処理 *
- (******************************)
- procedure checkOverflow(var val : valueType ; rr : real; ii : integer) ;
- begin
- if abs(rr) > LimitInt then cnvFloat(val,rr) { 整数演算限界 ・・・>実数演算 }
- else val.vi := ii
- end ;
-
- (*****************************)
- (* 加算処理 *)
- (*****************************)
- procedure add(var val1 : valueType; val2 : valueType) ;
- begin
- if val1.kind = int then
- if val2.kind = int then
- checkOverflow(val1, val1.vi+val2.vi, val1.vi+val2.vi)
- else cnvFloat(val1, val1.vi+val2.vr)
- else
- if val2.kind = int then val1.vr := val1.vr + val2.vi
- else val1.vr := val1.vr + val2.vr
- end ;
-
- (*****************************)
- (* 減算処理 *)
- (*****************************)
- procedure sub(var val1 : valueType; val2 : valueType) ;
- begin
- if val1.kind = int then
- if val2.kind = int then
- checkOverflow(val1, val1.vi-val2.vi, val1.vi-val2.vi)
- else cnvFloat(val1, val1.vi-val2.vr)
- else
- if val2.kind = int then val1.vr := val1.vr - val2.vi
- else val1.vr := val1.vr - val2.vr
- end ;
-
- (*****************************)
- (* 乗算処理 *)
- (*****************************)
- procedure mul(var val1 : valueType; val2 : valueType) ;
- begin
- if val1.kind = int then
- if val2.kind = int then
- checkOverflow(val1, val1.vi*val2.vi, val1.vi*val2.vi)
- else cnvFloat(val1, val1.vi*val2.vr)
- else
- if val2.kind = int then val1.vr := val1.vr * val2.vi
- else val1.vr := val1.vr * val2.vr
- end ;
-
- (****************************)
- (* 式の処理 *)
- (****************************)
- procedure expression(var val : valueType) ;
- var eVal : valueType ;
-
- (**************************)
- (* 項の処理 *)
- (**************************)
- procedure term(var Val : valueType) ;
- var tVal : valueType ;
-
- (***********************)
- (* 因子の処理 *)
- (***********************)
- procedure factor(var val : valueType) ;
- begin
- if ch = '(' then { 括弧記法の時 }
- begin { ( 式 ) の 処理を行う }
- read(ch) ;
- expression(val) ;
- if ch = ')' then read(ch)
- else error(SYNe) { 式の誤り }
- end
- else inputNumber(val)
- end {factor} ;
-
- begin { term }
- factor(val) ;
- while (ch = '*') or (ch = '/') do
- if ch = '*' then
- begin
- read(ch) ;
- factor(tVal) ;
- mul(val,tval) { val := val * tVal }
- end
- else { ch = '/' }
- begin
- read(ch) ;
- factor(tVal) ;
- if ((tVal.kind = int) and (tVal.vi = 0)) or { 0 除算チェック }
- (tVal.kind = rea) and (tVal.vr = 0.0) then error(DIVe) ;
- if val.kind = int then
- if tVal.kind = int then cnvFloat(val, val.vi / tVal.vi)
- else cnvFloat(val, val.vi / tVal.vr)
- else
- if tVal.kind = int then val.vr := val.vr / tVal.vi
- else val.vr := val.vr / tVal.vr
- end
- end {term} ;
-
- begin { expression }
- term(val) ;
- while (ch = '+') or (ch = '-') do
- if ch = '+' then
- begin
- read(ch) ;
- term(eVal) ;
- add(val,eVal) { val := val + eVval }
- end
- else { ch = '-' }
- begin
- read(ch) ;
- term(eVal) ;
- sub(val,eval) { val := val - eVval }
- end
- end {expression} ;
-
- (****************************)
- (* 開始処理 *)
- (****************************)
- procedure start ;
- begin
- write('# ') ; { プロンプト出力 }
- read(ch) { 最初の文字を読み込む }
- end ;
-
- (****************************)
- (* メイン処理 *)
- (****************************)
- begin
- 1:
- start ;
- while (ch <> 'q') and (ch <> 'Q') do { q または Q で 電卓終了 }
- begin
- expression(val) ;
- if ch <> '=' then writeln('式の最後は''=''で終わってね.') ;
- if val.kind = int then writeln(val.vi)
- else writeln(val.vr) ;
- readln ; { 以降改行までの入力を無視する }
- oldVal := val ; { 変数x のために 今の値を退避 }
- start
- end
- end.