# Rules providing basic arithmetic operationsHAIKU_ZERO = + 0 ;HAIKU_ONE = + 1 ;HAIKU_PAD_9 = 0 1 2 3 4 5 6 7 8 ;# a > b <==> $(HAIKU_DIGIT_GREATER_$(a)[1$(b)])HAIKU_DIGIT_GREATER_0 = $(HAIKU_PAD_9) ;HAIKU_DIGIT_GREATER_1 = $(HAIKU_PAD_9) 1 ;HAIKU_DIGIT_GREATER_2 = $(HAIKU_PAD_9) 1 1 ;HAIKU_DIGIT_GREATER_3 = $(HAIKU_PAD_9) 1 1 1 ;HAIKU_DIGIT_GREATER_4 = $(HAIKU_PAD_9) 1 1 1 1 ;HAIKU_DIGIT_GREATER_5 = $(HAIKU_PAD_9) 1 1 1 1 1 ;HAIKU_DIGIT_GREATER_6 = $(HAIKU_PAD_9) 1 1 1 1 1 1 ;HAIKU_DIGIT_GREATER_7 = $(HAIKU_PAD_9) 1 1 1 1 1 1 1 ;HAIKU_DIGIT_GREATER_8 = $(HAIKU_PAD_9) 1 1 1 1 1 1 1 1 ;HAIKU_DIGIT_GREATER_9 = $(HAIKU_PAD_9) 1 1 1 1 1 1 1 1 1 ;# a + b == $(HAIKU_DIGIT_ADD_$(a)[1$(b)]) (carry ignored)HAIKU_DIGIT_ADD_0 = $(HAIKU_PAD_9) 0 1 2 3 4 5 6 7 8 9 ;HAIKU_DIGIT_ADD_1 = $(HAIKU_PAD_9) 1 2 3 4 5 6 7 8 9 0 ;HAIKU_DIGIT_ADD_2 = $(HAIKU_PAD_9) 2 3 4 5 6 7 8 9 0 1 ;HAIKU_DIGIT_ADD_3 = $(HAIKU_PAD_9) 3 4 5 6 7 8 9 0 1 2 ;HAIKU_DIGIT_ADD_4 = $(HAIKU_PAD_9) 4 5 6 7 8 9 0 1 2 3 ;HAIKU_DIGIT_ADD_5 = $(HAIKU_PAD_9) 5 6 7 8 9 0 1 2 3 4 ;HAIKU_DIGIT_ADD_6 = $(HAIKU_PAD_9) 6 7 8 9 0 1 2 3 4 5 ;HAIKU_DIGIT_ADD_7 = $(HAIKU_PAD_9) 7 8 9 0 1 2 3 4 5 6 ;HAIKU_DIGIT_ADD_8 = $(HAIKU_PAD_9) 8 9 0 1 2 3 4 5 6 7 ;HAIKU_DIGIT_ADD_9 = $(HAIKU_PAD_9) 9 0 1 2 3 4 5 6 7 8 ;# a - b == $(HAIKU_DIGIT_SUB_$(a)[1$(b)]) (carry ignored)HAIKU_DIGIT_SUB_0 = $(HAIKU_PAD_9) 0 9 8 7 6 5 4 3 2 1 ;HAIKU_DIGIT_SUB_1 = $(HAIKU_PAD_9) 1 0 9 8 7 6 5 4 3 2 ;HAIKU_DIGIT_SUB_2 = $(HAIKU_PAD_9) 2 1 0 9 8 7 6 5 4 3 ;HAIKU_DIGIT_SUB_3 = $(HAIKU_PAD_9) 3 2 1 0 9 8 7 6 5 4 ;HAIKU_DIGIT_SUB_4 = $(HAIKU_PAD_9) 4 3 2 1 0 9 8 7 6 5 ;HAIKU_DIGIT_SUB_5 = $(HAIKU_PAD_9) 5 4 3 2 1 0 9 8 7 6 ;HAIKU_DIGIT_SUB_6 = $(HAIKU_PAD_9) 6 5 4 3 2 1 0 9 8 7 ;HAIKU_DIGIT_SUB_7 = $(HAIKU_PAD_9) 7 6 5 4 3 2 1 0 9 8 ;HAIKU_DIGIT_SUB_8 = $(HAIKU_PAD_9) 8 7 6 5 4 3 2 1 0 9 ;HAIKU_DIGIT_SUB_9 = $(HAIKU_PAD_9) 9 8 7 6 5 4 3 2 1 0 ;# a * b == $(HAIKU_DIGIT_MULT_CARRY_$(a)[1$(b)]) $(HAIKU_DIGIT_MULT_$(a)[1$(b)])HAIKU_DIGIT_MULT_0 = $(HAIKU_PAD_9) 0 0 0 0 0 0 0 0 0 0 ;HAIKU_DIGIT_MULT_1 = $(HAIKU_PAD_9) 0 1 2 3 4 5 6 7 8 9 ;HAIKU_DIGIT_MULT_2 = $(HAIKU_PAD_9) 0 2 4 6 8 0 2 4 6 8 ;HAIKU_DIGIT_MULT_3 = $(HAIKU_PAD_9) 0 3 6 9 2 5 8 1 4 7 ;HAIKU_DIGIT_MULT_4 = $(HAIKU_PAD_9) 0 4 8 2 6 0 4 8 2 6 ;HAIKU_DIGIT_MULT_5 = $(HAIKU_PAD_9) 0 5 0 5 0 5 0 5 0 5 ;HAIKU_DIGIT_MULT_6 = $(HAIKU_PAD_9) 0 6 2 8 4 0 6 2 8 4 ;HAIKU_DIGIT_MULT_7 = $(HAIKU_PAD_9) 0 7 4 1 8 5 2 9 6 3 ;HAIKU_DIGIT_MULT_8 = $(HAIKU_PAD_9) 0 8 6 4 2 0 8 6 4 2 ;HAIKU_DIGIT_MULT_9 = $(HAIKU_PAD_9) 0 9 8 7 6 5 4 3 2 1 ;HAIKU_DIGIT_MULT_CARRY_0 = $(HAIKU_PAD_9) 0 0 0 0 0 0 0 0 0 0 ;HAIKU_DIGIT_MULT_CARRY_1 = $(HAIKU_PAD_9) 0 0 0 0 0 0 0 0 0 0 ;HAIKU_DIGIT_MULT_CARRY_2 = $(HAIKU_PAD_9) 0 0 0 0 0 1 1 1 1 1 ;HAIKU_DIGIT_MULT_CARRY_3 = $(HAIKU_PAD_9) 0 0 0 0 1 1 1 2 2 2 ;HAIKU_DIGIT_MULT_CARRY_4 = $(HAIKU_PAD_9) 0 0 0 1 1 2 2 2 3 3 ;HAIKU_DIGIT_MULT_CARRY_5 = $(HAIKU_PAD_9) 0 0 1 1 2 2 3 3 4 4 ;HAIKU_DIGIT_MULT_CARRY_6 = $(HAIKU_PAD_9) 0 0 1 1 2 3 3 4 4 5 ;HAIKU_DIGIT_MULT_CARRY_7 = $(HAIKU_PAD_9) 0 0 1 2 2 3 4 4 5 6 ;HAIKU_DIGIT_MULT_CARRY_8 = $(HAIKU_PAD_9) 0 0 1 2 3 4 4 5 6 7 ;HAIKU_DIGIT_MULT_CARRY_9 = $(HAIKU_PAD_9) 0 0 1 2 3 4 5 6 7 8 ;# pragma mark - Number Operationsrule NormalizeNum number{# NormalizeNum <number> ;local sign ;if $(number[1]) = "-" || $(number[1] = "+" {sign = $(number[1]) ;number = $(number[2-]) ;} else {sign = "+" ;}# cut off leading zeroslocal number = [ FReverse $(number) ] ;while $(number[1]) = 0 {number = $(number[2-]) ;}number = [ FReverse $(number) ] ;# zero is respresented as + 0if ! $(number) {number = 0 ;sign = "+" ;}return $(sign) $(number) ;}rule Num string : dontExit{# Num <number string> [ : <dontExit> ] ;# split the string into three parts: sign, digits, and remainderlocal temp = [ Match ([^0-9]*)([0-9]+)(.*) : $(string) ] ;# there must be digits, but there must not be a remainderif ! $(temp[2]) || $(temp[3]) {if $(dontExit) {return ;}Exit "Not a number" ;}# get the signlocal number ;if ! $(temp[1]) {number = "+" ;} else if $(temp[1]) = "+" || $(temp[1]) = "-" {number = $(temp[1]) ;} else {if $(dontExit) {return ;}Exit "Not a number (sign)" ;}# split the digitstemp = $(temp[2]) ;while $(temp[1]) {# split off the last digittemp = [ Match (.*)([0-9]) : $(temp[1]) ] ;number += $(temp[2]) ;}# normalizereturn [ NormalizeNum $(number) ] ;}rule Num2String number{# Num2String <number> ;local sign = $(number[1]) ;if $(sign) = "+" {sign = "" ;}number = [ FReverse $(number[2-]) ] ;return $(sign)$(number:J=) ;}rule NumGreaterAbs a : b{# NumGreaterAbs <a> : <b> ;# we compare from least to most significant digitlocal cmp = 0 ;while $(a) && $(b) {# chop off the first digitlocal da = $(a[1]:E=0) ;local db = $(b[1]:E=0) ;a = $(a[2-]) ;b = $(b[2-]) ;if $(da) != $(db) {if $(HAIKU_DIGIT_GREATER_$(da)[1$(db)]) {cmp = 1 ;} else {cmp = -1 ;}}}# a is greater, if b is not longer and a is either longer or equally long# and greater according to the digits comparisonif ! $(b) && ( $(a) || $(cmp) = 1 ) {return 1 ;}return ;}rule AddNumAbs a : b{# AddNum <a> : <b> ;local result ;local carry ;while $(a) || $(b) || $(carry) {# chop off the first digitlocal da = $(a[1]:E=0) ;local db = $(b[1]:E=0) ;a = $(a[2-]) ;b = $(b[2-]) ;# add carry to the first digitif $(carry) {local daa = $(HAIKU_DIGIT_ADD_1[1$(da)]) ;carry = $(HAIKU_DIGIT_GREATER_$(da)[1$(daa)]) ;da = $(daa) ;}# add digitslocal dr = $(HAIKU_DIGIT_ADD_$(da)[1$(db)]) ;if $(HAIKU_DIGIT_GREATER_$(da)[1$(dr)]) {carry = 1 ;}result += $(dr) ;}return $(result) ;}rule SubNumAbs a : b{# SubNum <a> : <b> ;local result ;local carry ;while $(a) && ( $(b) || $(carry) ) {# chop off the first digitlocal da = $(a[1]:E=0) ;local db = $(b[1]:E=0) ;a = $(a[2-]) ;b = $(b[2-]) ;# sub carry from the first digitif $(carry) {local daa = $(HAIKU_DIGIT_SUB_$(da)[11]) ;carry = $(HAIKU_DIGIT_GREATER_$(daa)[1$(da)]) ;da = $(daa) ;}# sub digitslocal dr = $(HAIKU_DIGIT_SUB_$(da)[1$(db)]) ;if $(HAIKU_DIGIT_GREATER_$(dr)[1$(da)]) {carry = 1 ;}result += $(dr) ;}if $(b) || $(carry) {Exit "Error: SubNumAbs: Can't subtract greater from smaller number." ;}return $(result) ;}rule NegNum a{# NegNum <a> ;if $(a[1]) = "+" {if $(a) = $(HAIKU_ZERO) {return $(a) ;}return "-" $(a[2-]) ;} else {return "+" $(a[2-]) ;}}rule AddNum a : b{# AddNum <a> : <b> ;local signa = $(a[1]) ;local signb = $(b[1]) ;a = $(a[2-]) ;b = $(b[2-]) ;if $(signa) = $(signb) {return $(signa) [ AddNumAbs $(a) : $(b) ] ;} else {local result ;if [ NumGreaterAbs $(a) : $(b) ] {result = $(signa) [ SubNumAbs $(a) : $(b) ] ;} else {result = $(signb) [ SubNumAbs $(b) : $(a) ] ;}return [ NormalizeNum $(result) ] ;}}rule SubNum a : b{# SubNum <a> : <b> ;return [ AddNum $(a) : [ NegNum $(b) ] ] ;}rule MultNumAbsDigit a : digit{# MultNumAbsDigit <a> : <digit> ;local digitMultiples = $(HAIKU_DIGIT_MULT_$(digit)) ;local digitCarries = $(HAIKU_DIGIT_MULT_CARRY_$(digit)) ;local result ;local carry = 0 ;while $(a) || $(carry) != 0 {# chop off the first digitlocal da = $(a[1]:E=0) ;a = $(a[2-]) ;local dr = $(digitMultiples[1$(da)]) ;# add carry to the resulting digitif $(carry) {local dra = $(HAIKU_DIGIT_ADD_$(dr)[1$(carry)]) ;carry = $(HAIKU_DIGIT_GREATER_$(dr)[1$(dra)]:E=0) ;dr = $(dra) ;}# new carrycarry = $(HAIKU_DIGIT_ADD_$(carry:E=0)[1$(digitCarries[1$(da)])]) ;result += $(dr) ;}return $(result) ;}rule MultNum a : b{# MultNum <a> : <b> ;# If one of the factors is 0, we save us computation and normalization.if $(a) = $(HAIKU_ZERO) || $(b) = $(HAIKU_ZERO) {return $(HAIKU_ZERO) ;}# get the sign for the resultlocal sign = "+" ;if $(a[1]) != $(b[1]) {sign = "-" ;}a = $(a[2-]) ;b = $(b[2-]) ;# multiply the individual digits of b with a and add up the resultlocal result = 0 ;local prefix ;while $(b) {local db = $(b[1]) ;b = $(b[2-]) ;local adb = $(prefix) [ MultNumAbsDigit $(a) : $(db) ] ;result = [ AddNumAbs $(result) : $(adb) ] ;prefix += 0 ;}return $(sign) $(result) ;}rule NumGreater a : b{local signa = $(a[1]) ;local signb = $(b[1]) ;a = $(a[2-]) ;b = $(b[2-]) ;if $(signa) = $(signb) {if $(signa) = "+" {return [ NumGreaterAbs $(a) : $(b) ] ;} else {return [ NumGreaterAbs $(b) : $(a) ] ;}} else {if $(signa) = "+" {return 1 ;} else {return ;}}}# pragma mark - Number String Operationsrule Inc a{# Inc <number string a> ;return [ Num2String [ AddNum [ Num $(a) ] : + 1 ] ] ;}rule Dec a{# Dec <number string a> ;return [ Num2String [ AddNum [ Num $(a) ] : - 1 ] ] ;}rule Neg a{# Neg <number string a> ;return [ Num2String [ NegNum [ Num $(a) ] ] ] ;}rule Add a : b{# Add <number string a> : <number string b> ;return [ Num2String [ AddNum [ Num $(a) ] : [ Num $(b) ] ] ] ;}rule Sub a : b{# Sub <number string a> : <number string b> ;return [ Num2String [ SubNum [ Num $(a) ] : [ Num $(b) ] ] ] ;}rule Mult a : b{# Mult <number string a> : <number string b> ;return [ Num2String [ MultNum [ Num $(a) ] : [ Num $(b) ] ] ] ;}rule Equal a : b{# Equal <number string a> : <number string b> ;if [ Num $(a) ] = [ Num $(b) ] {return 1 ;}return ;}rule Less a : b{# Less <number string a> : <number string b> ;return [ NumGreater [ Num $(b) ] : [ Num $(a) ] ] ;}rule Greater a : b{# Greater <number string a> : <number string b> ;return [ NumGreater [ Num $(a) ] : [ Num $(b) ] ] ;}rule LessOrEqual a : b{# LessOrEqual <number string a> : <number string b> ;if [ NumGreater [ Num $(a) ] : [ Num $(b) ] ] {return ;}return 1 ;}rule GreaterOrEqual a : b{# GreaterOrEqual <number string a> : <number string b> ;if [ NumGreater [ Num $(b) ] : [ Num $(a) ] ] {return ;}return 1 ;}# pragma mark - Expression Parserrule ParseAtom expression{# ParseAtom <expression> ;# expression: '(' expression ')' | numberif $(expression[1]) = "(" {local result = [ ParseExpression $(expression[2-]) ] ;if $(result[2]) != ")" {Exit "ParseAtom: Parse error: Expected \")\"." ;}return $(result[1]) $(result[3-]) ;} else {if ! $(expression) {Exit "ParseAtom: Parse error: Unexpected end of expression." ;}local num = [ Num $(expression[1]) : 1 ] ;if ! $(num) {Exit "ParseAtom: Parse error: Expected number instead of:"$(expression[1]) ;}return [ Num2String $(num) ] $(expression[2-]) ;}}rule ParseUnary expression{# ParseUnary <expression> ;# expression: ('+'/'-')* atomif ! $(expression) {Exit "ParseUnary: Parse error: Unexpected end of expression." ;}# eat all unary "+" and "-" operationslocal neg ;while $(expression[1]) = "+" || $(expression[1]) = "-" {if $(expression[1]) = "-" {if $(neg) {neg = ;} else {neg = 1 ;}}expression = $(expression[2-]) ;}local result = [ ParseAtom $(expression) ] ;if $(neg) {return [ Neg $(result[1]) ] $(result[2-]) ;}return $(result) ;}rule ParseTerm expression{# ParseTerm <expression> ;# expression: unary ('*' unary)*local result = [ ParseUnary $(expression) ] ;local product = $(result[1]) ;expression = $(result[2-]) ;while $(expression[1]) = "*" {# get the operationlocal operation ;operation = Mult ;# parse the next operandresult = [ ParseUnary $(expression[2-]) ] ;expression = $(result[2-]) ;# compute the productproduct = [ $(operation) $(product) : $(result[1]) ] ;}return $(product) $(expression) ;}rule ParseExpression expression{# ParseExpression <expression> ;# expression: term ('+'/'-' term)*local result = [ ParseTerm $(expression) ] ;local sum = $(result[1]) ;expression = $(result[2-]) ;while $(expression[1]) = "+" || $(expression[1]) = "-" {# get the operationlocal operation ;if $(expression[1]) = "+" {operation = Add ;} else {operation = Sub ;}# parse the next operandresult = [ ParseTerm $(expression[2-]) ] ;expression = $(result[2-]) ;# compute the sumsum = [ $(operation) $(sum) : $(result[1]) ] ;}return $(sum) $(expression) ;}rule Expr expression{# Expr <expression> ;# tokenize the expressionlocal tokens ;local string ;for string in $(expression) {while $(string) {local split = [ Match "[ \t]*(-|[()+*]|[0-9]*)(.*)" : $(string) ] ;if ! $(split[1]) {Exit "Expr: Syntax error: Invalid token: \"$(string)\"." ;}tokens += $(split[1]) ;string = $(split[2]) ;}}local result = [ ParseExpression $(tokens) ] ;if $(result[2-]) {Exit "Expr: Garbage at end of expression:" $(result[2-]) ;}return $(result[1]) ;}