Newsgroups: comp.lang.postscript
From: "luser.droog" <luser.dr...@gmail.com>
Date: Sun, 14 Oct 2012 04:43:10 -0500
Local: Sun, Oct 14 2012 5:43 am
Subject: Re: How to do Algebraic Mode in PS like the HP does?
luser.droog wrote:
http://devmaster.net/posts/2866/processing-arithmetic-expressions-wit...
> luser.droog wrote: >>> A little more searching led me to this:
>>> Looks very promising.
>> Another draft.
>> But I think this makes for a simple, extensible base. ?maybe?
> Added boolean and relational ops, and unary + and -.
backwards to the previous token to see if it was (once) a function name. Added function calls (must be defined in the /func dictionary),
And Comments!
531(1)04:35 AM:ps 0> cat infix4.ps
%a helper procedure
%the basis of the operator tables
[ /& {and} 9 true ]
[ /eq {eq} 6 true ]
[ /** {exp} 4 false ]
]
} forall currentdict end def
dup /prec exch dup length dict begin {
dup 0 get exch 2 get def } forall currentdict end def
dup /left exch dup length dict begin {
dup 0 get exch 3 get def } forall currentdict end def
pop
%prefix operators + (do nothing) and - (negate)
%postfix operator ! (factorial)
%recognized function names
%opstack utilities
} def
/oppop {
opptr -1 eq { /stackunderflow signalerror } if opstack opptr get /opptr opptr 1 sub def } def
%We process the string left-to-right, using the normal
%PS scanner `token` and call these procedures upon encountering %the various types in the object returned by `token` /process { dup type exec } def /booleantype { } def % "Data" types: leave on stack (do nothing) /integertype { } def /realtype { } def /stringtype { % process substring % and perform function call depending upon /prev /prev load null ne { func /prev load known { exch pop %func name may have resolved to PS -operator- } if } if eval /prev load null ne { func /prev load known { func /prev load get exec } if } if } def
/nametype { % process an operator or variable lookup
%(name)= dup == flush %prev is oper or null: prefix
oper /prev load known {
} ifelse
} def
%process a prefix operator
/unop { %(pre)= dup == flush dup preop exch known { preop exch get cvx %load the prefix op frop preop % this resolves to a high-precedence operator % which, of course, "happens" to be unary. % There's no "stack-checking" going on anywhere. doop % pop opstack until prec(tos) <|<= prec(op) }{ %not an op dup where { exch get } if %load variable % It is this step which is WRONG for % function names. But we discard it and % check /prev to workaround. } ifelse } def
/binop {
%(bin)= dup == flush dup oper exch known { %it IS an operator doop % pop opstack until prec(tos) <|<= prec(op) }{ %not an op dup where { exch get } if %load variable % Ditto. ^^^^^ WRONG ^^^^ } ifelse } def
/doop {
/op exch def % stash the op in /op { opptr 0 lt { exit } if %opstack empty: return prec opstack opptr get get % prec(tos) prec /op load get % prec(tos) prec(op) left /op load get % prec(tos) prec(op) left(op) { ge }{ gt }ifelse % prec(tos)>|>=prec(op) { %prec(tos)>prec(op) oper oppop get exec %pop and apply }{ exit %tos sufficiently popped for now } ifelse } loop /op load oppush % push the op } def
% (infix-expression) eval result
%the main entry point % expects a string (or other token source) on stack % upon completion, yields the result of evaluation on the stack /eval { 10 dict begin /opstack 50 array def /opptr -1 def /tok null def { %loop until no more tokens token { exch /rem exch def %stash the remainder /tok exch /prev /tok load def def %stash /tok and /prev /tok load process %process tok according to type rem }{ exit %no more tokens: exit the loop } ifelse } loop %apply and pop the opstack until empty opptr 1 add { oper oppop get exec } repeat end } def %Some simplistic testing
} def
testeval
%argument assignment shortcut
%simple example
(1 1 dist =)= 1 1 dist =
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
| ||||||||||||||