PDA

View Full Version : Exponents using variants ... and death thereby.



Robert Kosek
26-05-2007, 02:34 PM
I'm going to do something I don't normally do, but I'll give full source along with this. It's just a test bed, but part of a bigger project.

One of my annoyances is that data is either arbitrarily compiled, thus never changing except when you recompile, or or stored in an external format. Sometimes these external formats are just too heavy and bloated for a given purpose. Thus I was working on a makeshift parser and tokenizer which relies heavily upon the use of variants. If these wacky bugs continue I swear I'll switch to FPC!

Anyway. I made a very simple console application that takes an input string and tokenizes it into an array of strings. From there the first is a command followed by data. So to permit things like mixing integers and floats I started using variants. There are only 4 functions:

Sum: totals all following numbers regardless of format or type. Works like a charm.
Sub: Subtracts number 2 from number 1; also works like a charm.
Power: Calculates x1 to the x2 power; dies like Dracula with a stake in his chest.
Exit: <_<


What I have determined through the use of breakpoints is that in power the two numbers are never assigned, and that the output is never written. Almost as if that part of the code just isn't called at all; but is should be.

Anyone have any clues? I'm using Turbo Delphi with the hotfix rollup with the following code. I'm about to go mad! I have tried 3-4 different ways of assignment but I can't get variants in this section to function, or breakpoints either (anymore). Oddest of all, when I first added the functionality it WORKED -- now it doesn't. I will assuredly need variants once I start the true function call implementations!

Remember, I am showing this for troubleshooting purposes; don't use it without asking me first. Here's the code:

program tokenizer;

&#123;$APPTYPE CONSOLE&#125;

uses
SysUtils, Math, Variants;

type TDynStrArray = array of string;

function tokenize&#40;line&#58; string&#41;&#58; TDynStrArray;
var temp&#58; string;
l,i&#58; cardinal;
inStr,wasStr&#58; boolean;
begin
l &#58;= 0;
temp &#58;= line;
instr &#58;= false;

while temp <> '' do begin
if l > length&#40;result&#41;-1 then
SetLength&#40;result, l+8&#41;;
wasStr &#58;= false;
for i &#58;= 1 to Length&#40;temp&#41; do
case temp&#91;i&#93; of
'`'&#58; begin inStr &#58;= not inStr; wasStr &#58;= true; end;
' ',#0&#58; if not inStr then Break;
end;
if not wasStr then
result&#91;l&#93; &#58;= copy&#40;temp,1,i-1&#41;
else
result&#91;l&#93; &#58;= copy&#40;temp,2,i-3&#41;;
Delete&#40;temp,1,i&#41;;
inc&#40;l&#41;;
end;

setlength&#40;result,l&#41;;
end;

var inputtokens&#58; TDynStrArray;
input&#58; string;
i&#58; integer;
exit&#58; boolean = false;
v1,v2&#58; variant;

begin
writeln&#40;'Enter tokens seperated by spaces, strings delimited by `''s.'&#41;;

repeat
v1 &#58;= 0;
v2 &#58;= 0;
input &#58;= '';
setlength&#40;inputtokens,0&#41;;

write&#40;'> '&#41;; readln&#40;input&#41;;
writeln;

if input <> '' then begin
inputtokens &#58;= tokenize&#40;input&#41;;

for i &#58;= 0 to Length&#40;inputtokens&#41; - 1 do
writeln&#40;'Token'#9'#',i,'&#58; "',inputtokens&#91;i&#93;,'"'&#41;;
writeln;

if inputtokens&#91;0&#93; = 'sum' then begin
v1 &#58;= Variant&#40;inputtokens&#91;1&#93;&#41; + 0;
for i &#58;= 2 to length&#40;inputtokens&#41; - 1 do begin
v2 &#58;= inputtokens&#91;i&#93;;
v1 &#58;= v1 + v2;
end;

writeln&#40;'Sum&#58;'#9,v1&#41;;
end else if inputtokens&#91;0&#93; = 'sub' then
if length&#40;inputtokens&#41; >= 3 then
writeln&#40;'Sub&#58;'#9,Variant&#40;inputtokens&#91;1&#93;&#41; - Variant&#40;inputtokens&#91;2&#93;&#41;&#41;
else if inputtokens&#91;0&#93; = 'pwr' then
if length&#40;inputtokens&#41; >= 3 then begin
v1 &#58;= 0.0 + Math.Power&#40;StrToFloatDef&#40;inputtokens&#91;1&#93;,0&#41;,StrToFl oatDef&#40;inputtokens&#91;2&#93;,0.0&#41;&#41;;
writeln&#40;'Power&#58;'#9,v1&#41;;
end else writeln&#40;'Error, PWR given too few parameters.'&#41;
else
writeln&#40;'Unknown command "',inputtokens&#91;0&#93;,'"'&#41;;

exit &#58;= pos&#40;'exit',input&#41; > 0;

end;

writeln;
until &#40;exit&#41;;
end.

(Someone needs to look into posting... I had to disable HTML to post this at all; it died between the list and the code, but the code wasn't wrapped correctly.)

Robert Kosek
26-05-2007, 02:39 PM
I solved it myself. I realized that when I called "sub" with no parameters I ran into the "pwr" breakpoint that something was dreadfully wrong. It mixed the stupid if-the-else's up so I had to add some begin/end's to make sure it worked properly.

:roll:

Here's the working code for those interested:
program tokenizer;

&#123;$APPTYPE CONSOLE&#125;

uses
SysUtils, Math&#123;, Variants&#125;;

type TDynStrArray = array of string;

function tokenize&#40;line&#58; string&#41;&#58; TDynStrArray;
var temp&#58; string;
l,i&#58; cardinal;
inStr,wasStr&#58; boolean;
begin
l &#58;= 0;
temp &#58;= line;
instr &#58;= false;

while temp <do> length&#40;result&#41;-1 then
SetLength&#40;result, l+8&#41;;
wasStr &#58;= false;
for i &#58;= 1 to Length&#40;temp&#41; do
case temp&#91;i&#93; of
'`'&#58; begin inStr &#58;= not inStr; wasStr &#58;= true; end;
' ',#0&#58; if not inStr then Break;
end;
if not wasStr then
result&#91;l&#93; &#58;= copy&#40;temp,1,i-1&#41;
else
result&#91;l&#93; &#58;= copy&#40;temp,2,i-3&#41;;
Delete&#40;temp,1,i&#41;;
inc&#40;l&#41;;
end;

setlength&#40;result,l&#41;;
end;

var inputtokens&#58; TDynStrArray;
input&#58; string;
i&#58; integer;
exit&#58; boolean = false;
v1,v2&#58; variant;

begin
writeln&#40;'Enter tokens seperated by spaces, strings delimited by `''s.'&#41;;

repeat
v1 &#58;= 0;
v2 &#58;= 0;
input &#58;= '';
setlength&#40;inputtokens,0&#41;;

write&#40;'> '&#41;; readln&#40;input&#41;;
writeln;

if input <then>= 3 then
writeln&#40;'Sub&#58;'#9,Variant&#40;inputtokens&#91;1&#93;&#41; - Variant&#40;inputtokens&#91;2&#93;&#41;&#41;;
end else if inputtokens&#91;0&#93; = 'pwr' then
if length&#40;inputtokens&#41; >= 3 then begin
v1 &#58;= 0.0 + Math.Power&#40;StrToFloatDef&#40;inputtokens&#91;1&#93;,0&#41;,StrToFl oatDef&#40;inputtokens&#91;2&#93;,0.0&#41;&#41;;
writeln&#40;'Power&#58;'#9,v1&#41;;
end else writeln&#40;'Error, PWR given too few parameters.'&#41;
else
writeln&#40;'Unknown command "',inputtokens&#91;0&#93;,'"'&#41;;

exit &#58;= pos&#40;'exit',input&#41; > 0;

end else writeln&#40;'Enter something I can process first.'&#41;;

writeln;
until &#40;exit&#41;;
end.