25b12e83ae
operate manually on digit lists, so they are certainly not fast and shouldn't be used excessively, but at least it's possible to do calculations in Jam now, should the need arise. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20596 a95241bf-73f2-0310-859d-f6bbb57e9c96
606 lines
13 KiB
Plaintext
606 lines
13 KiB
Plaintext
# 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 <number> ;
|
|
|
|
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 <number string> [ : <dontExit> ] ;
|
|
|
|
# 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 <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 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 <a> : <b> ;
|
|
|
|
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 <a> : <b> ;
|
|
|
|
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 <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 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 <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 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 <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 Parser
|
|
|
|
|
|
rule ParseAtom expression
|
|
{
|
|
# ParseAtom <expression> ;
|
|
|
|
# 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> ;
|
|
|
|
# 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> ;
|
|
|
|
# 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> ;
|
|
|
|
# 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 <expression> ;
|
|
|
|
# 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]) ;
|
|
}
|