diff --git a/Jamrules b/Jamrules index f99d8c9258..a4d8b5edae 100644 --- a/Jamrules +++ b/Jamrules @@ -19,6 +19,7 @@ LOCATE on $(HCACHEFILE) $(JCACHEFILE) = $(HAIKU_BUILD_OUTPUT_DIR) ; # At the end include BuildSetup that sets up global variables etc. The # optional user-defined UserBuildConfig is included thereafter. include [ FDirName $(HAIKU_BUILD_RULES_DIR) HelperRules ] ; +include [ FDirName $(HAIKU_BUILD_RULES_DIR) MathRules ] ; include [ FDirName $(HAIKU_BUILD_RULES_DIR) BeOSRules ] ; include [ FDirName $(HAIKU_BUILD_RULES_DIR) ConfigRules ] ; include [ FDirName $(HAIKU_BUILD_RULES_DIR) DocumentationRules ] ; diff --git a/build/jam/MathRules b/build/jam/MathRules new file mode 100644 index 0000000000..5bae0c12d3 --- /dev/null +++ b/build/jam/MathRules @@ -0,0 +1,605 @@ +# 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 ; + 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]) ; +}