home::GIT::Parse-RPN::bUlsiebr::Cloinbt:r:ihPboaumrtese:ed::G:PIReTPr:Nl:(P3Da)orcsuem-eRnPtNa:t:ibolnib::lib::Parse::RPN(3) PPaarrssee--RRPPNN ((VV 22..xxxx)) -- IInnttrroodduuccttiioonn Parse::RPN - Is a minimalist RPN parser/processor (a little like FORTH) SSYYNNOOPPSSIISS use Parse::RPN; $result=rpn(string ...); @results=rpn(string ...); $error=rpn_error(); string... is a list of RPN operator and value separated by a coma in scalar mode RPN return the result of the calculation (If the stack contain more then one element, you receive a warning and the top value on the stack) in array mode, you receive the content of the stack after evaluation DDEESSCCRRIIPPTTIIOONN rpn() receive in entry a scalar of one or more elements coma separated and evaluate as an RPN (Reverse Polish Notation) command. The function split all elements and put in the stack. The operator are case sensitive. The operator are detect as is, if they are alone in the element of the stack. Extra space before or after are allowed (e.g "3,4,MOD" here MOD is an operator but it is not the case in "3,4,MOD 1") If element is not part of the predefined operator (dictionary), the element is push as a litteral. If you would like to put a string which is part of the dictionary, put it between quote or double-quote (e.g "3,4,'MOD'" here MOD is a literal and the evaluation return MOD) If the string contain a coma, you need also to quote or double-quote the string. (be care to close your quoted or double-quoted string) The evaluation follow the rule of RPN or FORTH or POSTCRIPT or pockect calcutor HP. Look on web for documentation about the use of RPN notation. I use this module in a application where the final user need to create an maintain a configuration file with the possibility to do calculation on variable returned from application. The idea of this module is comming from Math::RPN of Owen DeLong, owen@delong.com that I used for more then a year before some of my customer would like more ... rpn_error() return the last error from the evaluation (illegal division by 0, error from the PERL function execution...) each time that rpn() is call the rpn_error() is reinitianised. MMAATTHHEEMMAATTIICC ooppeerraattoorrss aa bb ++ return the result of 'a' + 'b' aa bb -- return the result of 'a' - 'b' aa bb ** return the result of 'a' * 'b' aa bb // return the result of 'a' / 'b' if b =0 return '' (to prevent exception raise) aa bb **** return the result of 'a' ** 'b' (exponant) aa 11++ return the result of 'a' +1 aa 11-- return the result of 'a' -1 aa 22-- return the result of 'a' -2 aa 22++ return the result of 'a' +2 aa bb MMOODD return the result of 'a' % 'b' aa AABBSS return the result of abs 'a' aa IINNTT return the result of INT 'a' aa ++-- return the result negate value of 'a' (- 'a' ) aa RREEMMAAIINN return the result of 'a' - int 'a' (fractional part of 'a' ) aa SSIINN return the result of sin 'a' ('a' in RADIAN) aa CCOOSS return the result of cos 'a' ('a' in RADIAN) aa TTAANN return the result of tan 'a' ('a' in RADIAN) aa CCTTAANN return the result of cotan 'a' ('a' in RADIAN) aa LLNN return the result of ln 'a' if = 0 return '' (to prevent exception raise) aa EEXXPP return the result of 'e' ** 'a' PPII return the value of PI (3.14159265358979) RREELLAATTIIOONNAALL ooppeerraattoorrss aa bb << return the result of 'a' < 'b' ( BOOLEAN value ) aa bb <<== return the result of 'a' <= 'b' ( BOOLEAN value ) aa bb >> return the result of 'a' > 'b' ( BOOLEAN value ) aa bb >>== return the result of 'a' >= 'b' ( BOOLEAN value ) aa bb ==== return the result of 'a' == 'b' ( BOOLEAN value ) 1 if a == b else 0 aa bb <<==>> return the result of 'a' <=> 'b' ( BOOLEAN value ) -1 if a < b ,0 if a == b, 1 if a > b aa bb !!== return the result of 'a' != 'b' ( BOOLEAN value ) 0 if a == b else 1 aa bb vv >><< return the 1 ( BOOLEAN value ) if c gretear than a but lower than b. Otherwise return 0 aa bb vv >>==<< return the 1 ( BOOLEAN value ) if c gretear or equal to a but lower or equal to b. Otherwise return 0 aa bb return the result of 'a' N< 'b' ( BOOLEAN value ) if a is ISNUM aa bb == return the result of 'a' N<= 'b' ( BOOLEAN value ) if a is ISNUM aa bb NN>> return the result of 'a' N> 'b' ( BOOLEAN value ) if a is ISNUM aa bb NN>>== return the result of 'a' N>= 'b' ( BOOLEAN value ) if a is ISNUM aa bb NN==== return the result of 'a' N== 'b' ( BOOLEAN value ) 1 if a == b and a ISNUM else 0 LLOOGGIICCAALL ooppeerraattoorrss aa bb OORR return the 1 one of the 2 argument are not equal to 0 aa bb AANNDD return the 0 one of the 2 argument are equal to 0 aa bb XXOORR return the 0 if the 2 argument are equal aa bb NNXXOORR return the 0 if the 2 argument are equal. Any non numeric elements is seen as a 0. aa NNOOTT return the 0 if the argument is not eqauk to 0 return the 1 if the argument is eqauk to 0 aa TTRRUUEE return the 1 if the top of stack is !=0 and if stack not empty aa FFAALLSSEE return the 0 if the top of stack is !=0 MMIISSCC ooppeerraattoorrss aa bb >>>> bitwise shift to the right shift the bits in a to the left of b level aa bb <<<< bitwise shift to the left shift the bits in a to the left of b level aa bb MMIINN return the result smallest of the 2 arguments aa bb MMAAXX return the result greatest of the 2 arguments aa VVAALL,,RREETT,, ""ooppeerraattoorr"" LLOOOOKKUUPP test with the "operator" the [a] value on each elements of VAL and if test succeed return the value from array RET with the same index the "operator" must be quoted to prevent evaluation aa VVAALL,,RREETT,, ""ooppeerraattoorr"" LLOOOOKKUUPPPP test with the perl "operator" the [a] value on each elements of VAL and if test succeed return the value from array RET with the same index the "operator" must be quoted to prevent evaluation aa VVAALL,,RREETT,,OOPPEE LLOOOOKKUUPPOOPP loop on each item of array VAL and test the value [ a ] with the operator from ope ARRAY against the corresponding value in array VAL and return the value from array RET with the same index aa VVAALL,,RREETT,,OOPPEE LLOOOOKKUUPPOOPPPP loop on each item of array VAL and test the value [ a ] with the perl operator from ope ARRAY against the corresponding value in array VAL and return the value from array RET with the same index TTIICCKK return the current time in ticks aa LLTTIIMMEE return the localtime coresponding to the ticks value 'a' the format is 'sec' 'min' 'hour' 'day_in_the_month' 'month' 'year' 'day_in_week' 'day_year' 'dayloight_saving' 'year' is the elapsed year since 1900 'month' start to 0 The format is the same as localtime() in perl aa GGTTIIMMEE return the gmtime coresponding to the ticks value 'a' the format is 'sec' 'min' 'hour' 'day_in_the_month' 'month' 'year' 'day_in_week' 'day_year' 'dayloight_saving' 'year' is the elapsed year since 1900 'month' start to 0 The format is the same as gmtime() in perl aa HHLLTTIIMMEE return the localtime coresponding to the ticks value 'a' in a human readable format aa HHGGTTIIMMEE return the gmtime coresponding to the ticks value 'a' in a human readable format aa HHTTTTPPTTIIMMEE return the ticks coresponding to the time value in a format accepted by HTTP::Date RRAANNDD return a random value in the range [0,1[ aa LLRRAANNDD return a random value in the range [0,'a'[ aa SSPPAACCEE return the number 'a' formated with space each 3 digits aa DDOOTT return the number 'a' formated with . (dot) each 3 digits aa NNOORRMM return the number 'a' normalize by slice of 1000 with extra power value "K", "M", "G", "T", "P" (or nothing if lower than 1000) aa NNOORRMM22 return the number 'a' normalize by slice of 1024 with extra power value "K", "M", "G", "T", "P" (or nothing if lower than 1024) aa UUNNOORRMM reverse function of NORM return the number from a 'a' with a sufix "K", "M", "G", "T", "P" (or nothing if lower than 1000) and calculate the real value base 1000 ( e.g 7k = 7000) aa UUNNOORRMM22 reverse function of NORM2 return the number from a 'a' with a sufix "K", "M", "G", "T", "P" (or nothing if lower than 1024) and calculate the real value base 1024 ( e.g 7k = 7168) aa OOCCTT return the decimal value for the HEX, BINARY or OCTAL value 'a' OCTAL is like '0nn' where n is in the range of 0-7 BINARY is like '0bnnn...' where n is in the range of 0-1 HEX is like '0xnnn' where n is in the range of 0-9A-F if no specific format convert as an hexadecimal by default aa OOCCTTSSTTRR22HHEEXX return a HEX string from a OCTETSTRING. useful when receiving an SNMP ASN.1 OCTETSTRING like mac address aa HHEEXX22OOCCTTSSTTRR return a OCTETSTRING string from a HEX useful when you need to check if an SNMP ASN.1 OCTETSTRING if matching the hex value provided aa DDDDEECC22SSTTRR return a string from a dotted DEC string useful when you need to manipulate an SNMP extension with 'exec' aa SSTTRR22DDDDEECC return a dotted DEC string to a string useful when you need to manipulate an SNMP extension with 'exec' ssttrriinngg aa OOIIDDSSEEAARRCCHHAALLLLVVAALL return all OID leaf from a snmpwalk macthing the REGEX a string are the OID walk list the OID walk result use this format: each snmpwalk entries are separated by ' # ' and inside each entriy , the OID and the VAL are separated by ' | ' '# .1.3.6.1.2.1.25.4.2.1.2.4704 | "TASKMGR.EXE" # .1.3.6.1.2.1.25.4.2.1.2.2692 | "winvnc4.exe" # .1.3.6.1.2.1.25.4.2.1.2.3128 | "CSRSS.EXE" # example: '# .1.3.6.1.2.1.25.4.2.1.2.488 | "termsrv.exe" # .1.3.6.1.2.1.25.4.2.1.2.688 | "Apache.exe" # .1.3.6.1.2.1.25.4.2.1.2.5384 | "aimsserver.exe" # .1.3.6.1.2.1.25.4.2.1.2.2392 | "Apache.exe" # .1.3.6.1.2.1.25.4.2.1.2.2600 | "cpqnimgt.exe" #,Apache\.exe,OIDSEARCHALLVAL' return: 688 2392 ssttrriinngg aa OOIIDDSSEEAARRCCHHAALLLLVVAALL return all OID leaf from a snmpwalk macthing the REGEX a ( case insensitive ) string are the OID walk list the OID walk result use this format: each snmpwalk entries are separated by ' # ' and inside each entriy , the OID and the VAL are separated by ' | ' '# .1.3.6.1.2.1.25.4.2.1.2.4704 | "TASKMGR.EXE" # .1.3.6.1.2.1.25.4.2.1.2.2692 | "winvnc4.exe" # .1.3.6.1.2.1.25.4.2.1.2.3128 | "CSRSS.EXE" # example: '# .1.3.6.1.2.1.25.4.2.1.2.488 | "termsrv.exe" # .1.3.6.1.2.1.25.4.2.1.2.688 | "Apache.exe" # .1.3.6.1.2.1.25.4.2.1.2.5384 | "aimsserver.exe" # .1.3.6.1.2.1.25.4.2.1.2.2392 | "Apache.exe" # .1.3.6.1.2.1.25.4.2.1.2.2600 | "cpqnimgt.exe" #,Apache\.exe,OIDSEARCHALLVALI' return: 688 2392 ssttrriinngg xx xx xx aa OOIIDDSSEEAARRCCHHLLEEAAFF return all VAL leaf from a snmpwalk when the OID leaf match each REGEX a is the number of leaf to pick from the stack x are all the leaf string are the OID walk list the OID walk result use this format: each snmpwalk entries are separated by ' # ' and inside each entriy , the OID and the VAL are separated by ' | ' '# .1.3.6.1.2.1.25.4.2.1.2.4704 | "TASKMGR.EXE" # .1.3.6.1.2.1.25.4.2.1.2.2692 | "winvnc4.exe" # .1.3.6.1.2.1.25.4.2.1.2.3128 | "CSRSS.EXE" # example: '# .1.3.6.1.2.1.25.4.2.1.7.384 | running # .1.3.6.1.2.1.25.4.2.1.7.688 | running # .1.3.6.1.2.1.25.4.2.1.7.2384 | invalid #,688,2384,2,OIDSEARCHLEAF' return: running invalid ssttrriinngg xx xx xx aa OOIIDDSSEEAARRCCHHLLEEAAFFII return all VAL leaf from a snmpwalk when the OID leaf match each REGEX a ( case insensitive ) is the number of leaf to pick from the stack x are all the leaf string are the OID walk list the OID walk result use this format: each snmpwalk entries are separated by ' # ' and inside each entriy , the OID and the VAL are separated by ' | ' '# .1.3.6.1.2.1.25.4.2.1.2.4704 | "TASKMGR.EXE" # .1.3.6.1.2.1.25.4.2.1.2.2692 | "winvnc4.exe" # .1.3.6.1.2.1.25.4.2.1.2.3128 | "CSRSS.EXE" # example: '# .1.3.6.1.2.1.25.4.2.1.7.384 | running # .1.3.6.1.2.1.25.4.2.1.7.688 | running # .1.3.6.1.2.1.25.4.2.1.7.2384 | invalid #,688,2384,2,OIDSEARCHLEAFI' return: running invalid SSTTRRIINNGG ooppeerraattoorrss aa bb EEQQ return the result of 'a' EQ 'b' ( BOOLEAN value ) aa bb NNEE return the result of 'a' NE 'b' ( BOOLEAN value ) aa bb LLTT return the result of 'a' LT 'b' ( BOOLEAN value ) aa bb GGTT return the result of 'a' GT 'b' ( BOOLEAN value ) aa bb LLEE return the result of 'a' LE 'b' ( BOOLEAN value ) aa bb GGEE return the result of 'a' GE 'b' ( BOOLEAN value ) aa bb CCMMPP return the result of 'a' CMP 'b' ( BOOLEAN value ) aa LLEENN return the length of 'a' aa bb CCAATT return the concatenation 'a' and 'b' aa bb CCAATTAALLLL return the concatenation all element on the stack aa bb RREEPP return the result of 'a' x 'b' duplicate 'a' by the number of 'x' aa RREEVV return the reverse of 'a' aa bb cc SSUUBBSSTTRR return the substring of 'c' starting at 'b' with the length of 'a' aa UUCC return 'a' in uppercase aa LLCC return 'a' in lowercase aa UUCCFFIIRRSSTT return 'a' with the first letter in uppercase aa LLCCFFIIRRSSTT return 'a' with the first letter in lowercase aa RR11 RR22 KK VV SSPPLLIITT22 split a with the REGEX R1 each result are splitted with the REGEX R2 the result are stored in the variable k and v # .1.3.6.1.2.1.25.3.3.1.2.768 | 48 # .1.3.6.1.2.1.25.3.3.1.2.769 | 38 # .1.3.6.1.2.1.25.3.3.1.2.771 | 42 # .1.3.6.1.2.1.25.3.3.1.2.770 | 58 #,\s?#\s?,\s\|\s,a,b,SPLIT2 return a with .1.3.6.1.2.1.25.3.3.1.2.768,.1.3.6.1.2.1.25.3.3.1.2.769,.1.3.6.1.2.1.25.3.3.1.2.771,.1.3.6.1.2.1.25.3.3.1.2.770 and b with 48,38,42,58 !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry SPLIT return the matched value WITHOUT the empty string of the beginning aa bb SSPPLLIITT return all splitted item of 'a' by the separator 'b' 'b' is a REGEX !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry !!! if the split match on the beginning of string, SPLIT return the matched value WITHOUT the empty string of the beginning aa bb SSPPLLIITTII return all splitted item of 'a' by the separator 'b' 'b' is a REGEX case insensitive !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry !!! if the split match on the beginning of string, SPLIT return the matched value WITHOUT the empty string of the beginning aa bb PPAATT return one or more occurance of 'b' in 'a' 'b' is a REGEX !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry aa bb PPAATTII return one or more occurance of 'b' in 'a' 'b' is a REGEX case insensitive !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry aa bb TTPPAATT test if the pattern 'b' is in 'a' 'b' is a REGEX !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry aa bb TTPPAATTII test if the pattern 'b' is in 'a' 'b' is a REGEX !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry aa bb cc SSPPAATT substitute the pattern 'b' by the pattern 'a' in 'c' 'b' and 'c' are a REGEX !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry aa bb cc SSPPAATTGG substitute the pattern 'b' by the pattern 'a' in 'c' as many time as possible (g flag in REGEX) 'b' and 'c' are a REGEX !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry aa bb cc SSPPAATTII substitute the pattern 'b' by the pattern 'a' in 'c'case insensitive (i flag in REGEX) 'b' and 'c' are a REGEX !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry aa bb cc SSPPAATTGGII substitute the pattern 'b' by the pattern 'a' in 'c' as many time as possible (g flag in REGEX) and case insensitive (1 flag in REGEX) 'b' and 'c' are a REGEX !!! becare, if you need to use : as a regex, you need to backslash to prevent overlap with new dictionary entry aa ...... zz PPRRIINNTTFF use the format 'z' to print the value(s) on the stack 7,3,/,10,3,/,%d %f,PRINTF -> 2 3.333333 see printf in perl aa bb PPAACCKK pack the value 'a' with the format 'b' 2004,06,08,a4 a2 a2,PACK result: 20040608 see pack in perl aa bb UUNNPPAACCKK unpack the value 'a' with the format 'b' 20040608,a4 a2 a2,PACK result: 2004,06,08 see unpack in perl aa bb IISSNNUUMM test if top of the stack is a number return 1 if if it is a NUMBER otherwise return 0 aa bb IISSNNUUMMDD test if top of the stack is a number delete the top element on the statck and return 1 if it is a NUMBER otherwise return 0 aa bb IISSIINNTT test if top of the stack is a integer (natural number) return 1 if if it is a INTEGER otherwise return 0 aa bb IISSIINNTTDD test if top of the stack is a integer (natural number) delete the top element on the statck and return 1 if it is a INTEGER otherwise return 0 aa bb IISSHHEEXX test if top of the stack is a hexadecimal value (starting with 0x or 0X or # ) return 1 if if it is a HEXADECIMAL otherwise return 0 aa bb IISSHHEEXXDD test if top of the stack is a hexadecimal value (starting with 0x or 0X or # ) delete the top element on the statck and return 1 if it is a HEXADECIMAL otherwise return 0 SSTTAACCKK ooppeerraattoorrss aa bb SSWWAAPP return 'b' 'a' aa bb OOVVEERR return 'a' 'b' 'a' aa DDUUPP return 'a' 'a' aa bb DDDDUUPP return 'a' 'b' 'a' 'b' aa bb cc RROOTT return 'b' 'c' 'a' aa bb cc RRRROOTT return 'c' 'a' 'b' DDEEPPTTHH return the number of elements on the stack aa bb PPOOPP remove the last element on the stack aa ...... zz PPOOPPNN remove the 'z' last element(s) from the stack aa bb cc dd ee nn RROOLLLL rotate the stack on 'n' element a,b,c,d,e,f,4,ROLL -> a b d e f c if n = 3 <=> ROT if -2 < n < 2 nothing is done if n < -1 ROLL in reverse order a,b,c,d,e,f,-4,ROLL -> a b f e d c To reveerse a stack content use this: a,b,c,d,e,f,DEPTH,+-,ROLL => f e d c b a aa PPIICCKK copy element from depth 'a' to the stack aa GGEETT get (remove) element from depth 'a' and put on top of stack aa bb PPUUTT put element 'a' at the level 'b' of the stack if 'b' greater than the stack put at first place if 'b' < 0 start to the reverse order of the stack aa bb DDEELL delete 'b' element on the stack from level 'a' 'a' and 'b' is get in absolute value aa FFIINNDD get the level of stack containing the exact value 'a' if no match, return 0 aa FFIINNDDKK keep the level of stack containing the exact value 'a' f no match, return an empty stack ( shortcut for a,FIND,KEEP ) aa SSEEAARRCCHH get the first level of stack containing the REGEX 'a' aa SSEEAARRCCHHII get the first level of stack containing the REGEX 'a' (cas insensitive) aa SSEEAARRCCHHIIAA get all level of stack containing the REGEX 'a' (cas insensitive) empty the stack and return all the index of item matching aa SSEEAARRCCHHAA get all level of stack containing the REGEX 'a' (cas sensitive) empty the stack and return all the index of item matching toto,toti,titi,tata,tota,tito,tutot,truc,tot,SEARCHA result: 8 7 4 2 aa SSEEAARRCCHHKK keep all level of stack containing the REGEX 'a' (cas sensitive) toto,toti,titi,tata,tota,tito,tutot,truc,tot,SEARCHK result: toto toti tota tutot aa SSEEAARRCCHHIIKK keep all level of stack containing the REGEX 'a' (cas insensitive) aa KKEEEEPP delete all element on the stack except the level 'a' if 'a' is deeper then stack, keep the stack untouched aa KKEEEEPPVV delete all element on the stack except the levels with indice in the var A 1,5,2,3,A,!!,a,b,c,d,e,f,g,i,A,KEEPV result: i d g aa KKEEEEPPVVVV keep element from array B with indice from ARRAY A 1,5,2,3,A,!!,a,b,c,d,e,f,g,i,8,B,!!,B,A,KEEPVV result: i d g bb aa KKEEEEPPNN keep 'b' element on the stack from level 'a' and delete all other element 'a' and 'b' is get in absolute value a,b,c,d,e,f,g,h,4,3,KEEPN result: c d e f bb aa KKEEEEPPRR delete all elements on the stack except the level 'a' and keep all element deeper than 'b' if 'a' is deeper then stack, keep the stack untouched a,b,c,d,e,f,g,h,6,3,KEEPR result: a b f cc bb aa KKEEEEPPRRNN keep 'b' element on the stack from level 'a' and keep all element deeper than 'c' if 'a' is deeper then stack, keep the stack untouched a,b,c,d,e,f,g,h,i,j,7,3,2,KEEPRN result: a b c g h i aa bb PPRREESSEERRVVEE keep element on the stack from level 'a' to level 'b' and delete all other element 'a' and 'b' is get in absolute value if 'a' > 'b' keep the reverse of selection (boustrophedon) aa bb CCOOPPYY copy element on the stack from level 'a' to level 'b' 'a' and 'b' is get in absolute value if 'a' > 'b' keep the reverse of selection (boustrophedon) aa SSUUMM sum the a element on top of the stack remove these a element and return the result value on the stack aa SSTTAATTSS STATS the a element on top of the stack remove these a element the new variable _SUM_, _MULT_, _ARITH_MEAN_, _GEOM_MEAN_, _QUAD_MEAN_ (= _RMS_), _HARM_MEAN_, _STD_DEV_, _SAMPLE_STD_DEV_, _VARIANCE_, DDIICCTTIIOONNAARRYY aanndd VVAARRSS ooppeerraattoorrss WWOORRDDSS return as one stack element the list of WORD in DICT separated by a | VVAARRSS return as one stack element the list of VARS separated by a | vv SSIIZZEE return the size of the variable on the stack vv PPOOPPVV remove return the first item of the variable on the stack vv SSHHIIFFTTVV remove return the latest item of the variable on the stack vv aa IINNDD return the element of the variable at the indice a ( ARRAY emulation ) vv IINNCC incremente (+ 1) the value of the variable on the statck vv DDEECC decremente (- 1) the value of the variable on the statck VVAARRIIAABBLLEE xxxxxx declare the variable 'xxx' (reserve memory) xxxx vvaarr !! set and delete from the stack the value xx to the variable 'var' xxxx vvaarr !!AA append to the variable and delete from the stack the value xx to the variable 'var' xx11 xx22 xx33 ...... nn vvaarr !!!! put and delete from the stack 'n' element(s) from the stack in the variable 'var' 'n' is in absolute value xx11 xx22 xx33 ...... nn vvaarr !!!!AA append and delete 'n' element(s) from the stack in the variable 'var' 'n' is in absolute value xx11 xx22 xx33 ...... nn vvaarr !!!!CC copy 'n' element(s) from the stack in the variable 'var' 'n' is in absolute value xx11 xx22 xx33 ...... nn vvaarr !!!!CCAA append 'n' element(s) from the stack in the variable 'var' 'n' is in absolute value xx11 xx22 xx33 ...... bb aa vvaarr !!!!!! put and delete ' element(s) from the stack in the variable 'var' starting at element 'a' to element 'b' 'a' and 'b' in absolute value if 'a' > 'b' keep the reverse of selection (boustrophedon) xx11 xx22 xx33 ...... bb aa vvaarr !!!!!!AA append and delete ' element(s) from the stack in the variable 'var' starting at element 'a' to element 'b' 'a' and 'b' in absolute value if 'a' > 'b' keep the reverse of selection (boustrophedon) xx11 xx22 xx33 ...... bb aa vvaarr !!!!!!CC copy element(s) on the stack in the variable 'var' starting at element 'a' to element 'b' 'a' and 'b' in absolute value if 'a' > 'b' keep the reverse of selection (boustrophedon) xx11 xx22 xx33 ...... bb aa vvaarr !!!!!!CC append element(s) on the stack in the variable 'var' starting at element 'a' to element 'b' 'a' and 'b' in absolute value if 'a' > 'b' keep the reverse of selection (boustrophedon) vvaarr @@ return the value of the variable 'var' ::xxxxxx nnaammee11 ;; create a new entry in the dictionary whith name name1 and store the progam xxx :: xxxxxx yyyyyy nnaammee11 PPEERRLL execute the PERL code with parameter(s) xxx yyy !!! be care if the perl code need to use a coma (,) you need to enclose the line inside double quote if you need double quote in code use qq{ ... } :: xxxxxx nnaammee11 PPEERRLLFFUUNNCC execute the PERL function name1 with the parameter xxx the default name space is "main::" It is possible tu use a specific name space the paramter are "stringified" e.g. ':,5,filename,save,PERLFUNC' call the function save("filename", 5); aa >>RR put 'a' on the return stack RR>> remove first element from the return stack and copy on the normal stack RRLL return the depth of the return stack RR@@ copy return stack on normal stack FFIILLEE ooppeerraattoorrss (( bbaassiicc IIOO )) ffiillee,, mmooddee ,, FFHH,, OOPPEENN OPEN a file and keep the filehandle in the variable X mode could be all combination of : 'r' ( read ), 'w' ( write ), 'c' ( create ), 't' ( truncate ), 'a'( append = seek to end ) FFHH,, SSTTAATT STAT the file using the handle stored in the var FH ( FH could also be a file path ) return the same content as perl stat. Keep in mind that the indice 0 from the perl array is the 1 fisrt stack level. To get the size of a file: /tmp/rpn,STAT,13,8,KEEPR OOFFFFSSEETT,, WWHHEENNCCEE,, FFHH,, SSEEEEKK SEEK of OFFSET in the file using the handle stored in the var FH if WHENCE = 0 seek from the beginning of the file if WHENCE = 1 seek from the current position if WHENCE = 2 seek from the end of the file ( offset must be < 0 ) ( see perldoc -f seek ) FFHH,, TTEELLLL TELL return the position in the file using the handle stored in the var FH FFHH,, CCLLOOSSEE CLOSE the file handle stored in the var FH NN,, FFHH,, GGEETTCC read and put on top of the stack N character from the filedscriptor stored in the variable FH to do a file slurp: /tmp/rpn,r,fh,OPEN,sh,STAT,13,6,KEEPR,fh,GETC,fh,CLOSE NN,, FFHH,, GGEETTCCSS read and put on the stack N character from the filedscriptor stored in the variable FH each character is pushed on the stack ( and then the stack is evalueted ) NN,, FFHH,, WWRRIITTEE put and delete N element from the stack to the filedscriptor stored in the variable FH NN,, FFHH,, WWRRIITTEELLIINNEE put and delete N element from the stack as a new line for each element to the filedscriptor stored in the variable FH to flush buffer, use 0,0,FH,SEEK FFHH,, RREEAADDLLIINNEE read and put on the stack a line from the filedscriptor stored in the variable FH LLOOOOPP aanndd DDEECCIISSIIOONN ooppeerraattoorrss aa IIFF xxxxxx TTHHEENN test the element on top of stack if == 1 execute 'xxx' block The loop is executed always one time aa IIFF zzzzzz EELLSSEE xxxxxx TTHHEENN test the element on top of stack if == 1 execute 'xxx' block if != 1 execute 'zzz' block The loop is executed always one time BBEEGGIINN xxxxxx WWHHIILLEE zzzzzz RREEPPEEAATT execute 'xxx' block test the element on top of stack if == 0 execute 'zzz' block and branch again at 'BEGIN' if != 0 end the loop The loop is executed always one time eenndd ssttaarrtt DDOO,,bblloocckk,,LLOOOOPP process 'block' with iterator from value 'start' until 'end' value,with increment of 1; The iterator variable is the second value on the stack (start argument) eenndd ssttaarrtt iinnccrreemmeenntt DDOO,,bblloocckk,,++LLOOOOPP process 'block' with iterator from value 'start' untill 'end' value,with increment of 'increment' This allow rational or negative value The iterator variable is the second value on the stack (start argument) UUsseeffuull ffuunnccttiioonnss ffoorr tthhee mmoodduullee ((nnoott rreellaatteedd ttoo tthhee RRPPNN llaanngguuaaggee)) _r_p_n___e_r_r_o_r_(_) function which return the debug info from the calculation (like a division by 0) rrppnn__sseeppaarraattoorr(( ''sseepp'' )) function to set a specific separator for the returned stack (default = space) This is useful when the result of rpn() is use inside another rpn() call OOPPEERRAATTOORRSS The operators get value from the stack and push the result on top In the following explanation, the stack is represented as a pair of brackets () and each elements by a pair of square barcket [] The left part is the state before evalutation and the right part is the state of the stack after evaluation Arithmetic operators --------------------- + ([a][b]) ([a+b]) - ([a][b]) ([a-b]) * ([a][b]) ([a*b]) / ([a][b]) ([a/b]) Becare if division by null return a blank value ** ([a][b]) ([a**b]) 1+ ([a]) ([a+1]) 1- ([a]) ([a-1]) 2+ ([a]) ([a+2]) 2- ([a]) ([a-2]) MOD ([a][b]) ([a%b]) ABS ([a]) ([ABS a]) INT ([a]) ([INT a]) +- ([a]) ([-a]) REMAIN ([a]) ([a- INT a]) Rationnal operators ------------------- SIN ([a]) ([SIN a]) Unit in radian COS ([a]) ([COS a]) Unit in radian TAN ([a]) ([TAN a]) Unit in radian CTAN ([a]) ([CTAN a]) Unit in radian LN ([a]) ([LOG a]) EXP ([a]) ([EXP a]) PI ([3.14159265358979]) Relational operator ---------------- < ([a][b]) ([1]) if [a]<[b] else ([0]) <= ([a][b]) ([1]) if [a]<=[b] else ([0]) > ([a][b]) ([1]) if [a]>[b] else ([0]) >= ([a][b]) ([1]) if [a]>=[b] else ([0]) == ([a][b]) ([1]) if [a]==[b] else ([0]) <=> ([a][b]) ([-1]) if [a]>[b],([1]) if [a]<[b], ([0])if [a]==[b] != ([a][b]) ([0]) if [a]==[b] else ([1]) TRUE ([a]) Return 1 if [a]>0 and exist FALSE ([a]) Return 0 if [a]>0 Logical operator ---------------- OR ([a][b]) ([1]) if [a] or [b] >0 AND ([a][b]) ([1]) if [a] and [b] >0 XOR ([a][b]) ([1]) if [a] and [b] are >0 or ==0 NOT ([a]) Return 0 if [a]>0, Return 1 if[a]==0, Other operator ---------------- >> ([a][b]) shift to the right the bits from [a] of [b] rank << ([a][b]) shift to the left the bits from [a] of [b] rank MIN ([a][b]) ([a]) if [a]<[b] else ([b]) MAX ([a][b]) ([a]) if [a]>[b] else ([b]) LOOKUP ([a] V R [ope] ) test [ a ] on all value of array V with the operator [ope] if succeed, return the value from array R at the succesfull indice LOOKUPP ([a] V R [ope] ) test [ a ] on all value of array V with the perl operator [ope] if succeed, return the value from array R at the succesfull indice LOOKUPOP ([a] V R O] ) test [ a ] on all value of array V with the operator from the array OPE with the same indice LOOKUPOPP ([a] V R O] ) test [ a ] on all value of array V with the perl operator from the array OPE with the same indice if succeed, return the value from array R at the succesfull indice TICK () ([time]) time in ticks LTIME ([a]) ([min][hour][day_in_the_month][month][year][day_in_week][day_year][daylight_saving] localtime of [a] like PERL GTIME ([a]) ([min][hour][day_in_the_month][month][year][day_in_week][day_year][daylight_saving] ([a]) gmtime of [a] like PERL HLTIME ([a]) ([a]) localtime human readeable HGTIME ([a]) gmtime human readeable RAND () ([rand]) a random numder between 0 and 1 LRAND ([a]) ([rand]) a random numder between 0 and [a] SPACE ([a]) Return [a] with space between each 3 digits DOT ([a]) Return [a] with dot (.) between each 3 digits NORM ([a]) Return [a] normalized by 1000 (K,M,G = 1000 * unit) NORM2 ([a]) Return [a] normalized by 1000 (K,M,G = 1024 * unit) OCT (|a|) Return the DECIMAL value from HEX,OCTAL or BINARY value |a| (see oct from perl) OCTSTR2HEX (|a|) Return a HEX string from a OCTETSTRING HEX2OCTSTR (|a|) Return a OCTETSTRING string from a HEX DDEC2STR (|a|) Return a string from a dotted DEC string STR2DDEC (|a|) Return a dotted DEC string to a string String operators ---------------- EQ ([a][b]) ([1]) if [a] eq [b] else ([0]) NE ([a][b]) ([1]) if [a] ne [b] else ([0]) LT ([a][b]) ([1]) if [a] lt [b] else ([0]) GT ([a][b]) ([1]) if [a] gt [b] else ([0]) LE ([a][b]) ([1]) if [a] le [b] else ([0]) GE ([a][b]) ([1]) if [a] ge [b] else ([0]) CMP ([a][b]) ([-1]) if [a] gt [b],([1]) if [a] lt [b], ([0])if [a] eq [b] LEN ([a]) ([LENGTH a]) CAT ([a][b]) ([ab]) String concatenation CATALL ([a][b]...[z]) ([ab...z]) String concatenation of all elements on the stack REP ([a][b]) ([a x b]) repeat [b] time the motif [a] REV ([a]) ([REVERSE a]) SUBSTR ([a][b][c]) ([SUBSTR [a], [b], [c]) get substring of [a] starting from [b] untill [c] UC ([a]) ([UC a]) LC ([a]) ([LC a]) UCFIRST ([a]) ([UCFIRST a]) LCFIRST ([a]) ([LCFIRST a]) PAT ([a][b]) ([r1]...) use the pattern [b] on the string [a] and return result if more then one result like $1, $2 ... return all the results PATI ([a][b]) ([r1]...) use the pattern CASE INSENSITIVE [b] on the string [a] and return result if more then one result like $1, $2 ... return all the results TPAT ([a][b]) ([r]) use the pattern [b] on the string [a] and return 1 if pattern macth otherwise return 0 TPATI ([a][b]) ([r]) use the pattern CASE INSENSITIVE [b] on the string [a] and return 1 if pattern macth otherwise return 0 SPLIT ([a][b]) split ([a]) using the pattern ([b]) and return all elements on stack SPLITI split ([a]) using the pattern CASE INSENSITIVE ([b])) and return all elements on stack SPLIT2 ([a][R1][R2][K][V]) split ([a]) using the pattern ([R1]), each result are splitted using the pattern ([R2]) the result are stored in the variables [K] and [V] SPAT ([a][b][c]) Do a pattern subsititution following this rule I<[c] =~s/[a]/[b]/> SPATG ([a][b][c]) Do a pattern subsititution following this rule I<[c] =~s/[a]/[b]/g> SPATI ([a][b][c]) Do a pattern subsititution following this rule I<[c] =~s/[a]/[b]/i> (case insensitive) SPATGI ([a][b][c]) Do a pattern subsititution following this rule I<[c] =~s/[a]/[b]/gi> (case insensitive) PRINTF ([a][b]...[x]) use the format present in [a] to print the value [b] to [x] the format is the same as (s)printf PACK ([a][b]...[x]) Do an unpack on variable [b] to [x] using format [b] UNPACK ([a][b]) Do an unpack on variable [b] using format [a] ISNUM ([a]) Test if a is a NUMBER return 1 if success ( [a] [1|0] ) Keep the value on the stack ISNUMD ([a]) Test if a is a NUMBER return 1 if success ( [1|0] ) Remove the value from the stack ISINT ([a]) Test if a is a INTEGER (natural number ) Return 1 if success ( [a] [1|0] ) Keep the value on the stack ISINTD ([a]) Test if a is a INTEGER (natural number ) Return 1 if success ( [1|0] ) Remove the value from the stack ISHEX ([a]) Test if a is a HEXADECIMAL (hex starting with 0x or 0X or # ) Return 1 if success ( [a] [1|0] ) Keep the value on the stack ISHEXD ([a]) Test if a is a HEXADECIMAL (hex starting with 0x or 0X or # ) Return 1 if success ( [1|0] ) Remove the value from the stack Stack operators --------------- SWAP ([a][b]) ([b][a]) OVER ([a][b]) ([a][b][a]) DUP ([a]) ([a][a]) DDUP ([a][b]) ([a][b][a][b]) ROT ([a][b][c]) ([b][c][a]) RROT ([a][b][c]) ([c][a][b]) DEPTH ([r1]...) ([re1]...[nbr]) Return the number of elements in the statck POP ([a][b]) ([a]) POPN ([a][b][c]...[x]) ([l]...[x]) remove [b] element from the stack (starting at [c]) SWAP2 ([a][b][c]) ([a][c][b]) ROLL ([a][b][c][d][e][n]) ([a][c][d][e][b]) rotate the [n] element of the stack (here [n]=4) if [n] =3 it is equivalent to ROT PICK ([a][b][c][d][e][n]) ([a][b][c][d][e][b]) copy element from depth [n] on top GET ([a][b][c][d][e][n]) ([a][b][c][d][e][b]) get element from depth [n] and put on top PUT ([a][b][c][d][v][n]) ([a][v][b][c][d]) put element [v] at level [n] (here [n]=3) DEL ([a][b]) delete [b] element on the stack from level [a] [a] and [b] is get in absolute value KEEPN ([a][b]) keep [b] element(s) on the stack from level [a] (and delete all other elements) [a] and [b] is get in absolute value KEEPR KEEPRN PRESERVE ([a][b]) keep element(s) on the stack from level [a] to level [b] (and delete all other elements) [a] and [b] is get in absolute value COPY ([a][b]) copy element(s) on the stack from level [a] to level [b] [a] and [b] is get in absolute value FIND ([a]) get the level of stack containing [a] SEARCH ([a]) get the level of stack containing the REGEX [a] SEARCHI ([a]) get the level of stack containing the REGEX [a] ( case insensitive ) SEARCHK ([a]) keep only level of stack matching the REGEX [a] SEARCHIK ([a]) keep only level of stack matching the REGEX [a] ( case insensitive ) KEEP ([a][b][c][d][e][n]) remove all elements of the stack except the element at deepth |n| Dictionary operators -------------------- WORDS () ([a])return as one stack element the list of WORD in DICT separated by a | VARS () ([a])return as one stack element the list of VARIABLE in VAR separated by a | INC ([a]) () increment (+1) the value of variable [a] DEC ([a]) () decrement (-1) the value of variable [a] VARIABLE ([a]) () create a entry in VAR for the variable [a] ! ([a][b]) store the value [a] in the variable [b] !A !! ([a][b][c]...[n] [var]) put and delete 'n' element(s) from the stack in the variable 'var' 'n' is in absolute value !!A !!C ([a][b][c]...[n] [var]) copy 'n' element(s) from the stack in the variable 'var' 'n' is in absolute value !!CA !!! ([a][b][c]...[n1] [n2] [var]) put and delete element(s) from the stack in the variable 'var' starting at element 'a' to element 'b' 'a' and 'b' in absolute value if 'a' > 'b' keep the reverse of selection (boustrophedon) !!!A !!!C ([a][b][c]...[n] [var]) copy 'element(s) from the stack in the variable 'var' starting at element 'a' to element 'b' 'a' and 'b' in absolute value if 'a' > 'b' keep the reverse of selection (boustrophedon) !!!CA @ ([a]) ([a]) return the value of the variable [a] : xxx yyy ; create a new word (sub) into the dictionary with the xxx "code" and name yyy : xxx yyy PERLFUNC execute the PERL function yyy with parameter(s) yyy the default name space is "main::" It is possible tu use a specific name space : xxx yyy PERL execute the PERL code xxx ; yyy File oprator ------------- OPEN STAT SEEK TELL CLOSE GETC GETCS READLINE WRITE WRITELINE Return Stack operators ---------------------- >R ([a]) put ^a$ on the return stack R> () remove first element from the return stack and copy on the normal RL () return the depth of the return stack R@ () copy return stack ion normal stack LOOP and DECISION operators --------------------------- [a] IF [..xxx] THEN Test the element on top of stack if ==0, execute 'xxx' block The loop is executed always one time [a] IF [...zzz...] ELSE [..xxx...] THEN Test the element on top of stack if ==0, execute 'xxx' block if != 0 execute 'zzz' block The loop is executed always one time BEGIN xxx WHILE zzz REPEAT Execute 'xxx' block Test the element on top of stack if ==0 execute 'zzz' block and branch again to BEGIN if != 0 end the loop The loop is executed always one time [a] [b] DO [...xxx...] LOOP ([a][b]) process block [...xxx...] with iterator from value [b] untill [a] value, with increment of 1; The iterator variable is '_I_' (read only and scoop only the DO ... LOOP block) [a] [b] DO [...xxx...] [c] +LOOP ([a][b]) process block [...xxx...] with iterator from value [b] untill [a] value, with increment of [c]; The iterator variable is '_I_' (read only and scoop only the DO ... LOOP block) EEXXAAMMPPLLEESS use Parse::RPN; $test ="3,5,+"; $ret = rpn($test); # $ret = 8 $test = "Hello World,len,3,+"; $ret = rpn($test); # $ret = 14 $test = "'Hello,World',len,3,+"; $ret = rpn($test); # $ret = 14 $test = "'Hello,World,len,3,+"; ---------^-----------^- $ret = rpn($test); # $ret = 8 with a warning because the stack is not empty ([Hello] [8]) # be care to close your quoted string $test = "'Hello world','or',PAT,'or',EQ,IF,'string contain or',ELSE,'No or in string',THEN" $ret = rpn($test); # $ret = "Contain a coma" $test = "'Hello world','or',TPAT,IF,'string contain or',ELSE,'No or in string',THEN"; $ret = rpn($test); # $ret = "string contain or" $test = "3,10,/,5,+,82,*,%b,PRINTF"; $ret = rpn($test); # $ret = "110110010" $test = "3,10,/,5,+,82,*,%016b,PRINTF"; $ret = rpn($test); # $ret = "0000000110110010" $test = "55,N,pack,B32,unpack,^0+(?=\d), ,spat,'+',ds"; $ret = rpn($test); # $ret = 110111 $test = "7,3,/,10,3,/,%d %f,PRINTF"; @ret = rpn($test); # @ret = 2 3.333333 $test = "VARIABLE,a,0,a,!,##,b,BEGIN,bbbb,a,INC,a,@,4,>,WHILE,####,a,@,****,REPEAT"; @ret =rpn($test); # @ret = ## b bbbb #### 1 **** bbbb #### 2 **** bbbb #### 3 **** bbbb or $test = "0,a,!,##,b,BEGIN,bbbb,a,INC,a,@,4,>,WHILE,####,a,@,****,REPEAT"; # the VARIABLE declaration is optionel @ret =rpn($test); # @ret = ## b bbbb #### 1 **** bbbb #### 2 **** bbbb #### 3 **** bbbb #### 4 **** bbbb $test = "VARIABLE,a,0,a,!,z,0,5,-1,DO,a,INC,6,1,2,DO,A,_I_,+LOOP,#,+LOOP,##,a,@"; @ret =rpn($test); # @ret = z A 3 A 5 A 7 # A 3 A 5 A 7 # A 3 A 5 A 7 # A 3 A 5 A 7 # A 3 A 5 A 7 # A 3 A 5 A 7 # ## 6 $test = 'a,b,c,d,e,f,g,h,i,5,2,V1,!!!,uuu,V1,SIZE' $ret =rpn($test); # $ret = a b c d i uuu 4 $test = "1,2,3,4,5,6,7,8,9,3,KEEP"; $ret =rpn($test); # $ret = 7 $test = "1,2,3,4,5,6,7,8,9,30,KEEP"; $ret =rpn($test); # $ret = 1,2,3,4,5,6,7,8,9 $test = "h,g,f,e,d,c,b,a,4,3,DEL"; $ret =rpn($test); # $ret = h,c,b,a $test = 'test for a split,\s,SPLIT,DEPTH'; $ret =rpn($test); # $ret = test,for,a,split,4 $test = '# .1.3.6.1.2.1.25.3.3.1.2.768 | 48 # .1.3.6.1.2.1.25.3.3.1.2.769 | 38 # .1.3.6.1.2.1.25.3.3.1.2.771 | 42 # .1.3.6.1.2.1.25.3.3.1.2.770 | 58 #,\s?#\s?,\s\|\s,a,b,SPLIT2 $ret = rpn($test) $ret = rpn(a,@); # $ret = .1.3.6.1.2.1.25.3.3.1.2.768,.1.3.6.1.2.1.25.3.3.1.2.769,.1.3.6.1.2.1.25.3.3.1.2.771,.1.3.6.1.2.1.25.3.3.1.2.770 $ret = rpn(b,@); # $ret = 48,38,42,58 $test = "h,g,f,e,d,c,b,a,4,3,KEEPN""; ret =rpn($test); # @ret = g,f,e,d sub Test { my $a = shift; my $b = shift; my $c = $a/$b; print "a=$a\tb=$b\ttotal=$c\n"; return $c; } $test = ":,5,6,Test,PERLFUNC"; @ret =rpn($test); # call the function "Test" from the main package (the caller) with parameter 5,6 and return result (in @ret) $test = ":,05,11,01,0,0,0,Time::Local::timelocal,PERLFUNC"; @ret =rpn($test); # @ret = 1133391600 $test = "1,2,3,+,:, my $b=7, "open LOG , qq{ >/tmp/log }",print LOG time,PERL"; @ret =rpn($test); # @ret = 1,5 and the file /tmp/log contain a line with the tick time. $test = "11,55,*,5,2,401,+,:,my $b=,SWAP,CAT, "open LOG , qq{ >/tmp/log }",print LOG $b.qq{ \n },PERL" @ret =rpn($test); # @ret =1 2 3 1 (the latest 1 is the succes result return) and the file /tmp/log contain a line with 403 + a cariage return $test = 'mb,tb,gb,mb,kb,4,V,!!,12,9,6,3,4,R,!!,V,R,"TPATI",LOOKUP' @ret =rpn($test); # @ret = 6 $test = '5,1,2,3,4,5,5,V,!!," "," ",ok," ",nok,5,R,!!,V,R,"<=",LOOKUPP' @ret =rpn($test); # @ret = nok $test = '3,1,2,3,4,5,5,V,!!,a,b,ok,d,nok,5,R,!!,"<","<","<","<","<",5,O,!!,V,R,O,LOOKUPOPP' @ret =rpn($test); # @ret = d $test = 1,2,3,4,2,5,2,10,7,DEPTH,1,DO,MAX,LOOP' @ret =rpn($test); # @ret = 10 ( = search the MAX in the stack ) $test = 'toto,tata,tota,tato,titi,tito,toti,tot,SEARCHA,DEPTH,r,!!,res1,res2,res3,res4,res5,res6,res7,res8,r,SIZE,DUP,s,!,1,DO,r,POPV,PICK,st,!A,LOOP,DEPTH,POPN,st,@' @ret =rpn($test); # @ret = res2 res4 res8 The small tool 'RPN.pl' provide an easy interface to test quickly an RPN. This include two test functions named 'save' and 'restore' Try RPN.pl to get a minimal help. Take a look to the minimalistic code, and put RPN.pl in your path. Sample of use: RPN.pl -r '1,2,3,:,123,100,+,7,*,test,save,PERLFUNC' save in file '/tmp/test' the value '1561' (whithout CR/LF) and return 1 2 3 1 AAUUTTHHOORR Fabrice Dulaunoy It is a full rewrite from the version 1.xx to allow DICTIONNARY use and STRUCTURE control Thanks to the module Math::RPN from Owen DeLong, for the idea of using RPN in a config file SSEEEE AALLSSOO Math-RPN from Owen DeLong, TTOODDOO Error processing, stack underflow... CCRREEDDIITTSS Thank's to Stefan Moser for the idea to call a perl function from the rpn() and also for pin-pointing an error in stack return. LLIICCEENNSSEE Under the GNU GPL2 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Parse::RPN Copyright (C) 2004 2005 2006 2007 2008 2009 2010 DULAUNOY Fabrice Parse::RPN comes with ABSOLUTELY NO WARRANTY; for details See: L This is free software, and you are welcome to redistribute it under certain conditions; PPOODD EERRRROORRSS Hey! TThhee aabboovvee ddooccuummeenntt hhaadd ssoommee ccooddiinngg eerrrroorrss,, wwhhiicchh aarree eexxppllaaiinneedd bbeellooww:: Around line 578: Unterminated N<...> sequence Deleting unknown formatting code N<> Around line 593: Unterminated N<...> sequence Deleting unknown formatting code N<> perl v5.14.2 ho2m0e1:3:-G0I4T-:0:9Parse-RPN::blib::lib::Parse::RPN(3)