# Rules providing basic arithmetic operations HAIKU_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 Operations rule NormalizeNum number { # NormalizeNum ; local sign ; if $(number[1]) = "-" || $(number[1] = "+" { sign = $(number[1]) ; number = $(number[2-]) ; } else { sign = "+" ; } # cut off leading zeros local number = [ FReverse $(number) ] ; while $(number[1]) = 0 { number = $(number[2-]) ; } number = [ FReverse $(number) ] ; # zero is respresented as + 0 if ! $(number) { number = 0 ; sign = "+" ; } return $(sign) $(number) ; } rule Num string : dontExit { # Num [ : ] ; # split the string into three parts: sign, digits, and remainder local temp = [ Match ([^0-9]*)([0-9]+)(.*) : $(string) ] ; # there must be digits, but there must not be a remainder if ! $(temp[2]) || $(temp[3]) { if $(dontExit) { return ; } Exit "Not a number" ; } # get the sign local 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 digits temp = $(temp[2]) ; while $(temp[1]) { # split off the last digit temp = [ Match (.*)([0-9]) : $(temp[1]) ] ; number += $(temp[2]) ; } # normalize return [ NormalizeNum $(number) ] ; } rule Num2String number { # Num2String ; local sign = $(number[1]) ; if $(sign) = "+" { sign = "" ; } number = [ FReverse $(number[2-]) ] ; return $(sign)$(number:J=) ; } rule NumGreaterAbs a : b { # NumGreaterAbs : ; # we compare from least to most significant digit local cmp = 0 ; while $(a) && $(b) { # chop off the first digit local 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 comparison if ! $(b) && ( $(a) || $(cmp) = 1 ) { return 1 ; } return ; } rule AddNumAbs a : b { # AddNum : ; local result ; local carry ; while $(a) || $(b) || $(carry) { # chop off the first digit local da = $(a[1]:E=0) ; local db = $(b[1]:E=0) ; a = $(a[2-]) ; b = $(b[2-]) ; # add carry to the first digit if $(carry) { local daa = $(HAIKU_DIGIT_ADD_1[1$(da)]) ; carry = $(HAIKU_DIGIT_GREATER_$(da)[1$(daa)]) ; da = $(daa) ; } # add digits local 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 : ; local result ; local carry ; while $(a) && ( $(b) || $(carry) ) { # chop off the first digit local da = $(a[1]:E=0) ; local db = $(b[1]:E=0) ; a = $(a[2-]) ; b = $(b[2-]) ; # sub carry from the first digit if $(carry) { local daa = $(HAIKU_DIGIT_SUB_$(da)[11]) ; carry = $(HAIKU_DIGIT_GREATER_$(daa)[1$(da)]) ; da = $(daa) ; } # sub digits local 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 ; if $(a[1]) = "+" { if $(a) = $(HAIKU_ZERO) { return $(a) ; } return "-" $(a[2-]) ; } else { return "+" $(a[2-]) ; } } rule AddNum a : b { # AddNum : ; 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 : ; return [ AddNum $(a) : [ NegNum $(b) ] ] ; } rule MultNumAbsDigit a : digit { # MultNumAbsDigit : ; 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 digit local da = $(a[1]:E=0) ; a = $(a[2-]) ; local dr = $(digitMultiples[1$(da)]) ; # add carry to the resulting digit if $(carry) { local dra = $(HAIKU_DIGIT_ADD_$(dr)[1$(carry)]) ; carry = $(HAIKU_DIGIT_GREATER_$(dr)[1$(dra)]:E=0) ; dr = $(dra) ; } # new carry carry = $(HAIKU_DIGIT_ADD_$(carry:E=0)[1$(digitCarries[1$(da)])]) ; result += $(dr) ; } return $(result) ; } rule MultNum a : b { # MultNum : ; # 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 result local 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 result local 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 Operations rule Inc a { # Inc ; return [ Num2String [ AddNum [ Num $(a) ] : + 1 ] ] ; } rule Dec a { # Dec ; return [ Num2String [ AddNum [ Num $(a) ] : - 1 ] ] ; } rule Neg a { # Neg ; return [ Num2String [ NegNum [ Num $(a) ] ] ] ; } rule Add a : b { # Add : ; return [ Num2String [ AddNum [ Num $(a) ] : [ Num $(b) ] ] ] ; } rule Sub a : b { # Sub : ; return [ Num2String [ SubNum [ Num $(a) ] : [ Num $(b) ] ] ] ; } rule Mult a : b { # Mult : ; return [ Num2String [ MultNum [ Num $(a) ] : [ Num $(b) ] ] ] ; } rule Equal a : b { # Equal : ; if [ Num $(a) ] = [ Num $(b) ] { return 1 ; } return ; } rule Less a : b { # Less : ; return [ NumGreater [ Num $(b) ] : [ Num $(a) ] ] ; } rule Greater a : b { # Greater : ; return [ NumGreater [ Num $(a) ] : [ Num $(b) ] ] ; } rule LessOrEqual a : b { # LessOrEqual : ; if [ NumGreater [ Num $(a) ] : [ Num $(b) ] ] { return ; } return 1 ; } rule GreaterOrEqual a : b { # GreaterOrEqual : ; if [ NumGreater [ Num $(b) ] : [ Num $(a) ] ] { return ; } return 1 ; } # pragma mark - Expression Parser rule ParseAtom expression { # ParseAtom ; # expression: '(' expression ')' | number if $(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: ('+'/'-')* atom if ! $(expression) { Exit "ParseUnary: Parse error: Unexpected end of expression." ; } # eat all unary "+" and "-" operations local 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: unary ('*' unary)* local result = [ ParseUnary $(expression) ] ; local product = $(result[1]) ; expression = $(result[2-]) ; while $(expression[1]) = "*" { # get the operation local operation ; operation = Mult ; # parse the next operand result = [ ParseUnary $(expression[2-]) ] ; expression = $(result[2-]) ; # compute the product product = [ $(operation) $(product) : $(result[1]) ] ; } return $(product) $(expression) ; } rule ParseExpression expression { # ParseExpression ; # expression: term ('+'/'-' term)* local result = [ ParseTerm $(expression) ] ; local sum = $(result[1]) ; expression = $(result[2-]) ; while $(expression[1]) = "+" || $(expression[1]) = "-" { # get the operation local operation ; if $(expression[1]) = "+" { operation = Add ; } else { operation = Sub ; } # parse the next operand result = [ ParseTerm $(expression[2-]) ] ; expression = $(result[2-]) ; # compute the sum sum = [ $(operation) $(sum) : $(result[1]) ] ; } return $(sum) $(expression) ; } rule Expr expression { # Expr ; # tokenize the expression local 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]) ; }