uses sysutils; const oper_char = ['+','-','*','/','%','^','(',')']; type SyntaxError = class(Exception); MathError = class(Exception); DivZero = class(Exception); Tok_Type = (_UNDEF, _NUMBER, _OPERATOR, _FUNC, _END); TokenString = string[16]; tbase = class tokType: Tok_Type; constructor create; end; topertoken = class(tbase) private FValue: char; public constructor loadfromstring(const s: string; var p: integer); constructor stop; property Value: char read FValue write FValue; end; tnumbertoken = class(tbase) private FValue: double; public constructor loadfromstring(const s: string; var p: integer); property Value: double read FValue write FValue; end; tcalc = object function proceed(): double; constructor create(lpszCommand: string); destructor destroy(); virtual; private TokenValue: tbase; procedure SetFunction(lpszCommand: string); procedure GetToken(); virtual; function mul_div(): double; protected pCurrPos: integer; _Function: string; function add_sub(): double; function prim(): double; virtual; end; constructor tbase.create; begin end; constructor topertoken.stop; begin TokType := _END; end; constructor topertoken.loadfromstring(const s: string; var p: integer); begin Value := s[p]; inc(p); TokType := _OPERATOR; end; constructor tnumbertoken.loadfromstring(const s: string; var p: integer); var st: string; begin st := ''; while s[p] in ['0'..'9','.'] do begin st := st + s[p]; inc(p); end; FValue := strtofloat(st); TokType := _NUMBER; end; destructor tcalc.destroy; begin end; constructor tcalc.create(lpszCommand: string); begin TokenValue := TBase.Create; SetFunction(lpszCommand); end; procedure tcalc.SetFunction(lpszCommand: string); begin _Function := lpszCommand; pCurrPos := 1; end; function tcalc.proceed(): double; begin if _Function = '' then raise SyntaxError.Create('No Expression'); exit( add_sub() ); end; function tcalc.add_sub(): double; var left: double; begin left := mul_div(); while(true) do begin case (TokenValue as topertoken).fvalue of '+': left := left + mul_div(); '-': left := left - mul_div(); else exit(left); end; end; end; function tcalc.mul_div(): double; var left: double; d, power, unused: double; p1, i: integer; begin left := prim(); while(true) do begin if TokenValue.tokType = _OPERATOR then case (TokenValue as topertoken).fvalue of '(': begin if pCurrPos > 1 then dec(pCurrPos); left := left * prim(); end; '*': left := left * prim(); '/': begin d := prim(); if d = 0 then raise DivZero.Create(''); left := left / d; end; '%': begin d := prim(); if d = 0 then raise DivZero.Create(''); left := trunc(left) mod trunc(d); end; '^': begin power := prim(); if (left = 0) and (power <= 0) then raise MathError.Create('Raising zero into power that is not greater than 0'); repeat if frac(power) = 0 then begin p1 := trunc(power); power := left; for i := 1 to pred(p1) do left := left * power; if p1 < 0 then left := 1 / left; break; end; if left < 0 then raise MathError.Create('Raising number, that is less than zero into not integer power'); left := exp(ln(left) * power); break; until false; end; else exit(left); end // case else exit(left); end; end; function tcalc.prim(): double; var T, angle: double; begin GetToken(); case TokenValue.tokType of _NUMBER: begin T := (TokenValue as tnumbertoken).fvalue; GetToken(); exit(T) end; _OPERATOR: begin case (TokenValue as topertoken).fvalue of '-': exit( -prim() ); '+': exit( prim() ); '(': begin T := add_sub(); if (TokenValue as topertoken).fvalue <> ')' then raise SyntaxError.Create(') expected'); GetToken(); exit(T); end; end; raise SyntaxError.Create('Incorrect operator'); end; else raise SyntaxError.Create('No Expression'); end; end; procedure tcalc.GetToken(); begin if pCurrPos > length(_Function) then begin TokenValue.Destroy; TokenValue := topertoken.stop; exit; end; while _Function[pCurrPos] = ' ' do inc(pCurrPos); if _Function[pCurrPos] in ['0'..'9'] then begin TokenValue.Destroy; TokenValue := tnumbertoken.LoadFromString(_Function, pCurrPos); end else if _Function[pCurrPos] in oper_char then begin TokenValue.Destroy; TokenValue := topertoken.LoadFromString(_Function, pCurrPos); end else begin TokenValue.Destroy; TokenValue := TBase.Create; end end; const line: string = '2*(2+43*1-17*3+(2+4*5)-5)'; // 22 var calculator: tcalc; begin try calculator.create(line); writeln('Answer is : ', calculator.proceed():15:7); except on DivZero do writeln('Error: Dividing by zero...'); on E: SyntaxError do writeln('Syntax error: ' + E.Message); on E: MathError do writeln('Error while calculating :' + E.Message); end; end.