; Calculatrice RPN begin sub displayStack(stack) declare size, one, minusOne, elem let size = dcount(stack) if size = 0 then echonl "" return endif let one = 1 let minusOne = neg(one) foreach elem in size, one, minusOne echonl format(elem, @right, '0', 2):'> ':format(stack{elem}, @right, ' ', 20) endfor except endsub ; declare rules, crules, Rule ; lex rules and compiled rules, Rule (pour echapper # 2 fois => #23#32#33) let crules = '' let rules = 'integer: int ' let rules{2} = 'fractionnal: frac ' let rules{3} = 'absolute: abs ' let rules{4} = 'negation: neg ' let rules{5} = 'round0: round0 ' let rules{6} = 'round1: round1 ' let rules{7} = 'round2: round2 ' let rules{8} = 'round3: round3 ' let rules{9} = 'round4: round4 ' let rules{10} = 'random: rnd ; random ' let rules{11} = 'varsys: @ (1,*,a-z) ' let rules{12} = 'number: (0,1,#23#32#332D) (1,13,0-9) . (0,5,0-9) ' ; corriger le double 'escape' car - est un car reserve lex (- => #2D => #23#32#33#23#33#32#23#34#34) car sinon compil/assembleur decode mal le - let rules{13} = 'integernumber: (0,1,#23#32#332D) (1,13,0-9) ' let rules{14} = 'minus: (1,1,#23#32#332D) ; - ' let rules{15} = 'plus: (1,1,#2B) ; + ' let rules{16} = 'multiply: (1,1,#2A) ; * ' let rules{17} = 'divide: (1,1,#2F) ; / ' let rules{18} = 'integerdivide: (1,1,#5C) ; \ ' let rules{19} = 'modulus: (1,1,#25) ; % ' let rules{20} = 'quit: quit ' let rules{21} = 'dup: dup ' let rules{22} = 'pop: pop ' let rules{23} = 'clear: clear ' let rules{24} = 'space: (1,1,#23#32#3320) ' let rules{25} = 'squareroot: sqrt ' let rules{26} = 'exponent: exp ' let rules{27} = 'other: (1,1,#23#32#3300-#23#32#33FF)' let rules = change(rules, @fm, @lf) part 1 let Rule = {} invoke lex&compile(rules, crules, Rule) part 2 ; todo mettre la sub qui suit dans le module lex (? pbm il faut 4/5 params) declare tok let tok = {} sub getToken(tokenList, tokenIndex, tokenNumber, value) let tokenNumber = tokenList{2, tokenIndex} if tokenNumber # '' then declare hexa let hexa = '' let hexa = tokenList{1, tokenIndex} invoke conv&fromHexa(hexa, value) endif ; si besoin invoke lex&getToken(tokenList, tokenIndex, tok) except endsub ; echonl "wcalc => + - * / \ % int frac abs neg sqrt exp rnd round0 round1 round2 round3 round4 @pi pop dup clear quit" ; declare value, stack, token, ind, ruleNumber, ruleValue let value = '' let token = '' let stack = '' loop do displayStack(stack) echo 'wcalc: ' let value = '' input value invoke lex&analyze(crules, value, token) ; ----------------------------------------------- ; token{1/2/3} en MV : chaine hexa, no token, ordinal_position let ind = 0 let ruleValue = '' let ruleNumber = 0 loop let ind = ind + 1 do getToken(token, ind, ruleNumber, ruleValue) breakon ruleNumber = '' continueon ruleNumber = Rule.space ; if ruleNumber = Rule.other then echonl 'Syntax error' break; ; ----------------------------------------------- elseif ruleNumber = Rule.dup then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack = insert(stack, stack{1}, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.pop then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack = remove(stack, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.clear then let stack = '' ; ----------------------------------------------- elseif ruleNumber = Rule.number or ruleNumber = Rule.integernumber then if dcount(stack) > 15 then echonl "Stack full error" else let stack = insert(stack, ruleValue, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.random then if dcount(stack) > 15 then echonl "Stack full error" else declare rnd let rnd = 0 invoke random&get(rnd) let stack = insert(stack, rnd, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.varsys then if dcount(stack) > 15 then echonl "Stack full error" else if ruleValue = '@pi' then let stack = insert(stack, @pi, 1) else echonl "Unknown constant" endif endif ; ----------------------------------------------- elseif ruleNumber = Rule.plus then if dcount(stack) < 2 then echonl "Stack underflow error" else let stack{2} = stack{2} + stack{1} let stack = remove(stack, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.minus then if dcount(stack) < 2 then echonl "Stack underflow error" else let stack{2} = stack{2} - stack{1} let stack = remove(stack, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.divide then if dcount(stack) < 2 then echonl "Stack underflow error" elseif stack{1} = 0 then echonl "Division by zero error" else let stack{2} = stack{2} / stack{1} let stack = remove(stack, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.integerdivide then if dcount(stack) < 2 then echonl "Stack underflow error" elseif stack{1} = 0 then echonl "Division by zero error" else let stack{2} = stack{2} \ stack{1} let stack = remove(stack, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.modulus then if dcount(stack) < 2 then echonl "Stack underflow error" elseif stack{1} = 0 then echonl "Division by zero error" else let stack{2} = stack{2} % stack{1} let stack = remove(stack, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.multiply then if dcount(stack) < 2 then echonl "Stack underflow error" else let stack{2} = stack{2} * stack{1} let stack = remove(stack, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.exponent then if dcount(stack) < 2 then echonl "Stack underflow error" else let stack{2} = exp(stack{2}, stack{1}) let stack = remove(stack, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.squareroot then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = sqrt(stack{1}) endif ; ----------------------------------------------- elseif ruleNumber = Rule.negation then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = neg(stack{1}) endif ; ----------------------------------------------- elseif ruleNumber = Rule.integer then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = int(stack{1}) endif ; ----------------------------------------------- elseif ruleNumber = Rule.fractionnal then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = frac(stack{1}) endif ; ----------------------------------------------- elseif ruleNumber = Rule.absolute then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = abs(stack{1}) endif ; ----------------------------------------------- elseif ruleNumber = Rule.round0 then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = round(stack{1}, 0) endif ; ----------------------------------------------- elseif ruleNumber = Rule.round1 then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = round(stack{1}, 1) endif ; ----------------------------------------------- elseif ruleNumber = Rule.round2 then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = round(stack{1}, 2) endif ; ----------------------------------------------- elseif ruleNumber = Rule.round3 then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = round(stack{1}, 3) endif ; ----------------------------------------------- elseif ruleNumber = Rule.round4 then if dcount(stack) < 1 then echonl "Stack underflow error" else let stack{1} = round(stack{1}, 4) endif endif ; ----------------------------------------------- breakon ruleNumber = Rule.quit endloop breakon ruleNumber = Rule.quit endloop echonl "Bye :)" except echonl "Exception line ":@exceptline if @part = 1 then declare err let err = 0 invoke lex&error(err) echonl "lex error : ":err endif end