Doing simple math from the command line (like PowerShell)

I like the way that one can do simple math from the PowerShell command line, example;
Code:
PS E:\utils> 52*4
208

Using the following alias;
Code:
e:\utils>alias unknown_cmd
echo %@eval[%@filter[0123456789.*+-/\,"%$"]]

...I can now do;
Code:
e:\utils>52*4
208
...from the TCC Command line.

Again, this is only for simple math, not for log(), fact(), MOD, etc.

When I enter an UNKNOWN_CMD, for example;
Code:
e:\utils>dze
TCC: No expression ""

...which is not pretty, but it works.

The next evolution of doing simple math from the TCC command line involved changing the alias to;
Code:
alias unknown_cmd=e:\utils\unknown_cmd.btm

...and creating UNKNOWN_CMD.BTM
Code:
@setlocal
@echo off
unalias unknown_cmd

set UseEval=N

iff %@isalpha[%$] eq 0 then
  iff %@isfloat[%$] eq 0 then
    iff %@isalnum[%$] eq 0 then
      set UseEval=Y
    endiff
  endiff
endiff

iff %UseEval eq Y then
  echo %@eval[%@filter[0123456789.*+-/\,"%$"]]
else
  on error gosub Catch
  %$
endiff

alias unknown_cmd=%_batchname

endlocal
quit

:Catch
echo       ?: %?
echo      _?: %_?
echo _Syserr: %_syserr

echo @isalpha: %@isalpha[%$]
echo @isfloat: %@isfloat[%$]
echo @isalnum: %@isalnum[%$]

Return

...returns;
Code:
e:\utils>dze
      ?: 0
     _?: 0
_Syserr: 536870913
@isalpha: 1
@isfloat: 0
@isalnum: 1

...which gives me more info than;
Code:
TCC: No expression ""

...but it works okay for me, as I use several AutoHotkey scripts for my non-conforming typing, for example;
Code:
e:\utils>type dre.ahk
:*:dre::dir

...which, when I type dre is automatically changed to dir.

Feel free to make modifications to this procedure for TCC command line math, but if you do, please share your modifications.

Joe
 
May 20, 2008
11,867
121
Syracuse, NY, USA
I have for a long time (and still do) just use an EVAL command, a wrapper for "ECHO %@EVAL[%$]". Once upon a time it was an alias; now it's a plugin. It gives the full power of @EVAL.

It's too bad an UNKNOWN_CMD alias or BTM can't invoke the default unknown command behavior. I wonder what would happen if a plugin UNKNOWN_CMD returned 0xFEDCBA98 (which means "I am disabled"). Would the default unknown command mechanism kick in? If so, perhaps one could capitalize on that.
 
May 20, 2008
11,867
121
Syracuse, NY, USA
Well, it does work. As a plugin, UNKNOWN_CMD can be selective and hand the job off to the built-in one. See my first test below. Now I have to think of a clever way to use it.

Code:
v:\> which unknown_cmd
unknown_cmd is a plugin command (4UTILS)

v:\> which foo
foo is an unknown command

v:\> foo
Aha! You issued "foo".

v:\> which bar
bar is an unknown command

v:\> bar
TCC: Unknown command "bar"
 

Charles Dye

Super Moderator
Staff member
May 20, 2008
4,596
97
Albuquerque, NM
prospero.unm.edu
Well, it does work. As a plugin, UNKNOWN_CMD can be selective and hand the job off to the built-in one. See my first test below. Now I have to think of a clever way to use it.

That turns out to be a whole lot trickier than I thought at first. For one thing, you can't rely on Evaluate()'s return code to tell you whether or not the string is a valid math expression.

For another, things like parentheses and angle brackets are long gone by the time an UNKNOWN_CMD handler sees the command line.
 
May 20, 2008
11,867
121
Syracuse, NY, USA
Yup! And testing the expression (with @EVAL[] or Evaluate()) could easily produce MAPM error messages. You can't even redirect those guys.

I think an UNKNOWN_CMD alias/plugin gets the whole command line. ... yes/no?
 
Nov 2, 2008
243
2
In the end, I use REXX. The basic calculator is fairly simple,
Code:
/* REXX */
numeric digits 15
parse arg chalk
interpret 'cheese=' chalk
say cheese
exit

If you want to add functions, you write these as subroutines. You can write specialised functions, or simply raid the AAT or some OS/2 bbs for the more generalised ones.

With little effort, you can add the likes of "datedif" to your calculator (add or subtract days, or the difference between two days).
 

Charles Dye

Super Moderator
Staff member
May 20, 2008
4,596
97
Albuquerque, NM
prospero.unm.edu
Hey @Charles Dye;
I've decided that your CMath plugin is a much better method than my "unknown_cmd" method.

I've added it to my TCSTART.BTM file, so that it's available whenever I need it.

Thanks!

Joe

Kind of a screwball approach, but it works.

For my part, mostly I use an EVAL alias. Similar to dcantor's, except it also saves the result to ANS.
 

samintz

Scott Mintz
May 20, 2008
1,534
22
Solon, OH, USA
The new %(()) syntax works as well. It is similar to Bash's $(()) syntax. An interesting side effect:
Code:
$ %((1+1))
TCC: Unknown command "2"
 
May 20, 2008
11,867
121
Syracuse, NY, USA
I used to use the aforementioned alias. Lately I've been using a simple plugin.

Code:
INT WINAPI EVAL ( WCHAR *psz )
{
    INT rv = Evaluate(psz);
    Printf(L"%s\r\n", psz);
    return rv;
}

It (the plugin) seems equal in speed to %(()). I'd guess the alias would be the same speed but I'm running into something odd when I try to test (sending output to NUL). With this alias

Code:
v:\> alias eval_alias
echo %@eval[%$]

I get

Code:
v:\> eval_alias log(5) - 2**10 + 7 -cos(0) + exp(10) + abs(-5)
21015.0752327192

v:\> eval_alias log(5) - 2**10 + 7 -cos(0) + exp(10) + abs(-5) > nul
1

Does anyone know what's happening there?

I worked around that difficulty and all three methods seem to be the same speed.

I vaguely remembered %(()) but I couldn't find it in the help. Where is it (other that "What's new" for some old version)?
 

samintz

Scott Mintz
May 20, 2008
1,534
22
Solon, OH, USA
The redirection is being treated as a comparison operator. And the result of the comparison is true or 1.

I found this is the What's New section of V23:
Code:
Variables:

You can return the result of a command with %(command).  This is the same as @EXEC[command] but a little easier to write.

%@ will return the batch file arguments (like %*), but they will all be double quoted.

Numeric variable expressions - %((...)) will evaluate and substitute the expression. For example:

echo %((3+5)) is the answer.

Conditional expressions - %[[...]] will evaluate the conditional expression, and return 0 if the exit status is true; 1 if it is not. For example:

echo %[[5 == 6]]
 

samintz

Scott Mintz
May 20, 2008
1,534
22
Solon, OH, USA
BTW - I typed "Numeric variable expressions" in the search tab of V28's help and it doesn't show up in the list.
 
May 20, 2008
11,867
121
Syracuse, NY, USA
Does anyone know what's happening there?
Here's what's happening. I don't like it and I doubt the behavior will be changed.

Code:
v:\> alias test `echo %@len[%$]`

v:\> test foo
3

v:\> test foo > NUL
9

I can work around that on the command line with (test foo) > NUL. But can I build protection against that into the alias itself? It seems this would affect all aliases which use %$ among the arguments to a variabe function.
 
The redirection is being treated as a comparison operator. And the result of the comparison is true or 1.

I found this is the What's New section of V23:
Code:
Variables:

You can return the result of a command with %(command).  This is the same as @EXEC[command] but a little easier to write.

%@ will return the batch file arguments (like %*), but they will all be double quoted.

Numeric variable expressions - %((...)) will evaluate and substitute the expression. For example:

echo %((3+5)) is the answer.

Conditional expressions - %[[...]] will evaluate the conditional expression, and return 0 if the exit status is true; 1 if it is not. For example:

echo %[[5 == 6]]

I found it in the v28 help file, after finding it in the v27 help file;

1628901831108.png


Joe
 
May 20, 2008
11,867
121
Syracuse, NY, USA
The redirection is being treated as a comparison operator. And the result of the comparison is true or 1.

I found this is the What's New section of V23:
Code:
Variables:

You can return the result of a command with %(command).  This is the same as @EXEC[command] but a little easier to write.

%@ will return the batch file arguments (like %*), but they will all be double quoted.

Numeric variable expressions - %((...)) will evaluate and substitute the expression. For example:

echo %((3+5)) is the answer.

Conditional expressions - %[[...]] will evaluate the conditional expression, and return 0 if the exit status is true; 1 if it is not. For example:

echo %[[5 == 6]]
Doesn't that require the %[[conditional]] syntax. That's not in my example.

And what about these (below). The help for @EVAL does not contain the word "condition[al]".

Code:
v:\> echo %@eval[2 < 1]
0

v:\> echo %@eval[2 > 1]
1
 
I can work around that on the command line with (test foo) > NUL. But can I build protection against that into the alias itself? It seems this would affect all aliases which use %$ among the arguments to a variabe function.
I don't think old versions did that. I don't have an old version installed to test. I have similar aliases that are now not working with redirection. For example:

Code:
C:\>alias bc
echo %@eval[%$]

C:\>bc 2+2
4

C:\>bc 2+2 > clip:
TCC: Syntax error "2+2 > clip:"
 
May 20, 2008
11,867
121
Syracuse, NY, USA
I don't think old versions did that. I don't have an old version installed to test. I have similar aliases that are now not working with redirection.
Hmmm! It fails as far back as v16.

Code:
v:\> ver
TCC  16.03.55   Windows 7 [Version 6.1.7601]

v:\> alias eval_alias
echo %@eval[%$]

v:\> eval_alias 2+2 > clip:
TCC: Syntax error "2+2 > clip:"

When packaged like this, it's OK.

Code:
v:\> do i=1 to 1 ( %comspec /c eval_alias 3+3 ^> clip: ) & echo %@clip[0]
6

or even like this

Code:
v:\> do i=1 to 1 ( %comspec /c eval_alias 4+4 > clip: ) & echo %@clip[0]
8

And while redirection has problems, piping does not.

Code:
v:\> eval_alias 5+5 | findstr /r .
10