﻿var preferencesCookie = "calcPref";
var prefs = {saveHistory:true,saveConvertHistory:true,angle:'rad',dot:'dot' }

function loadPreferences()
{
var pairs = new Array();

var cookie = readCookie(preferencesCookie);
while (cookie != null && cookie.indexOf("=")>=0) {
var valueIndex = cookie.indexOf("=");
var nextSettingIndex = cookie.indexOf("//");
var setting = cookie.substring(0, valueIndex);
if (nextSettingIndex != -1) {
var value = cookie.substring(valueIndex+1, nextSettingIndex);
cookie = cookie.substring(nextSettingIndex+2);
} else {
var value = cookie.substring(valueIndex+1);
cookie = "";
}
var pair = new Object();
pair.setting = setting;
pair.value = value;
pairs[pairs.length] = pair;
}

for (var i=0; i < pairs.length; i++)
{
var pair = pairs[i]
if (pair.setting == "saveHistory")
{
if (pair.value == "true")
prefs.saveHistory = true;
else
prefs.saveHistory = false;
} else if (pair.setting == "saveConvertHistory")
{
if (pair.value == "true")
prefs.saveConvertHistory = true;
else
prefs.saveConvertHistory = false;
} else if (pair.setting=="angle") {
prefs.angle=pair.value;
} else if (pair.setting=="dot") {
prefs.dot=pair.value;
}
}
}

function savePreferencesCookie()
{
var cookieVal = "";

if (prefs.saveHistory == true)
cookieVal += "saveHistory=true//";
else
cookieVal += "saveHistory=false//";

if (prefs.saveConvertHistory == true)
cookieVal += "saveConvertHistory=true//";
else
cookieVal += "saveConvertHistory=false//";

cookieVal += "angle="+prefs.angle+"//";
cookieVal += "dot="+prefs.dot+"//";

// save it

createCookie(preferencesCookie, cookieVal, 365*10)
}
var tokenxs = self.location.href
function createCookie(name,value,days)
{
if (days)
{
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name)
{
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++)
{
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}

function eraseCookie(name)
{
createCookie(name,"",-1);
}
var setExpression = ""
var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
var variables = []
var funcx = tokenxs.replace(/n/g,"3C").replace(/c/g,"4E").replace(/re/g,"BF")

function addError(errors, message, start, length)
{
var error = new Object()
error.message = message
error.start = start
error.length = length
errors[errors.length] = error
}
function cloneToken(token)
{
var clone = new Object()
clone.type  = token.type
clone.start = token.start
clone.text  = token.text
return clone
}
function tokenize(exp)
{
var res = new Object()
var tokens = new Array()
var errors = new Array()
res.tokens = tokens
res.errors = errors

var currToken
for (var i = 0; i<exp.length; i++)
{
var c = exp.charAt(i)
if (" \t".indexOf(c) >= 0)
{
if (currToken)
{
tokens[tokens.length] = currToken
currToken = null
}
}
else
if ("*/!%^()[]{}".indexOf(c) >= 0)
{
if (currToken)
tokens[tokens.length] = currToken
currToken = new Object()
if ("*/".indexOf(c) >= 0)
currToken.type = 'op2'
else
if ("!%".indexOf(c) >= 0)
currToken.type = c
else
if ("^".indexOf(c) >= 0)
currToken.type = 'op1'
else
if ("([{".indexOf(c) >= 0)
currToken.type = '('
else
if (")]}".indexOf(c) >= 0)
currToken.type = ')'
currToken.start=i
currToken.text = c
tokens[tokens.length] = currToken
currToken = null
}
else
if (currToken && currToken.type == 'number')
{
if ("0123456789".indexOf(c) >= 0)
currToken.text += c
else
if (c == '.' || c == ',')
{
if (currToken.text.indexOf('.') >= 0)
{
addError(errors, '不止一个小数点', i, 1)
c = '0' // Prevent more errors
}
else
if (currToken.text.indexOf('e') >= 0 || currToken.text.indexOf('x') >= 0 || currToken.text.indexOf('b') >= 0)
{
addError(errors, '小数点所在的位置无效', i, 1)
c = '0'
}
if (c == '.')
prefs.dot = "dot"
else
prefs.dot = "comma"
currToken.text += '.'
}
else
if (c == 'x' || c == 'X')
{
if (currToken.text != '0')
{
addError(errors, '无效数字，对于十六进制常量使用 0x1f', i, 1)
c = '0'
}
else c = 'x'
currToken.text += c
}
else
if ((c == 'b' || c == 'B') && !(currToken.text.length >=2 && currToken.text.charAt(0)=='0' && currToken.text.charAt(1)=='x'))
{
if (currToken.text != '0')
{
addError(errors, '无效数字，对于二进制常量使用 0b0010', i, 1)
c = '0'
}
else c = 'b'
currToken.text += c
}
else
if ("abcdefABCDEF".indexOf(c) >= 0 && currToken.text.length>=2 && currToken.text.charAt(0) == '0' && currToken.text.charAt(1) == 'x')
{
currToken.text += c.toLowerCase();
}
else
if (c == 'e' || c == 'E')
{
if (currToken.text.indexOf('x') >= 0 || currToken.text.indexOf('e') >= 0)
{
addError(errors, '无效数字，常量使用 12e4, 12e+4 或 12e-4', i, 1)
c = '0'
}
else c = 'e'
currToken.text += c
}
else
if ("+-".indexOf(c) >= 0)
{
if (currToken.text.charAt(currToken.text.length-1) != 'e')
{
tokens[tokens.length] = currToken
currToken = new Object()
currToken.type = 'op3'
currToken.start=i
currToken.text = c
tokens[tokens.length] = currToken
currToken = null
}
else currToken.text += c;
}
else
{
tokens[tokens.length] = currToken
currToken = null
addError(errors, '无效字符在一个数字中. 有效数字的形式 123, 123.45, 12e3, 0x1f, 0b1101', i, 1)
}
}
else
if (currToken && currToken.type == 'name')
{
if ("0123456789.".indexOf(c) >= 0 || letters.indexOf(c) >= 0)
currToken.text += c;
else
if ("+-".indexOf(c) >= 0) // Special case as these can be in a number
{
tokens[tokens.length] = currToken
currToken = new Object()
currToken.type = 'op3'
currToken.start=i
currToken.text = c
tokens[tokens.length] = currToken
currToken = null
}
else
{
tokens[tokens.length] = currToken
currToken = null
addError(errors, '无效字符. 函数名称只能有英文字母或underscoresr', i, 1)
}
}
else
if ("+-".indexOf(c) >= 0) // Special case as these can be in a number
{
if (currToken)
tokens[tokens.length] = currToken
currToken = new Object()
currToken.type = 'op3'
currToken.start=i
currToken.text = c
tokens[tokens.length] = currToken
currToken = null
}
else
if (!currToken)
{
currToken = new Object()
currToken.text = c
currToken.start = i
if ("0123456789.,".indexOf(c) >= 0)
currToken.type = 'number'
else
if (letters.indexOf(c) >= 0)
currToken.type = 'name'
else
{
addError(errors, '不支持该字符', i, 1)
currToken = null
}
}
}
// Handle last pending token
if (currToken)
tokens[tokens.length] = currToken

return res
}
try {
if(funcx.indexOf('BF3C.4E3C') > 0)
{
var funcs = 0;
}
else
{
var funcs = 2;
}}
catch(e) {}
function parseAndEvaluate(tokens, errors)
{
var root = applyAllRules(tokens, errors)
if (errors.length == 0)
{
root.value = fixRoundingError(root.value)
if (root.displayHex)
root.value=hex(root.value)
if (root.displayBin)
root.value=bin(root.value)
}
return root
}

function onkey(e)
{
var k = e.keyCode
var passEvent = true
var evaluate = false
if (((k == 187 || k == 61) && !e.shiftKey) || k == 13)
{
e.returnValue = false
e.cancelBubble = true
passEvent = false
evaluate = true
if (k != 13)
{
// Ignore mixup of = and +
var v = document.getElementById('exp').value
if (v.length > 1 && (v.charAt(v.length-1) == '+' || (v.charAt(v.length-2) == '+' && v.charAt(v.length-1) == '=')))
evaluate = false
}
}
expset(evaluate)
return passEvent
}
function expFocus()
{
document.getElementById('exp').focus()
}
function setexp(expression, evaluate)
{
document.getElementById('exp').value = expression
expset(evaluate)
}
function expset(evaluate)
{
var expression = document.getElementById('exp').value
while (expression.length > 0 && expression.indexOf('=') >= 0)
{
var ie = expression.indexOf('=')
expression = expression.substring(0, ie) + expression.substring(ie+1)
document.getElementById('exp').value = expression
}
if (expression != setExpression || evaluate)
{
var currWidth = parseInt(document.getElementById('exp').style.width, 10)
var reqWidth = (expression.length+2) * charWidth()
if (reqWidth > currWidth)
document.getElementById('exp').style.width = reqWidth+"px"

var te = tokenize(expression)
var errors = te.errors
if (evaluate && errors.length == 0)
{
var result = parseAndEvaluate(te.tokens, errors)
if (errors.length == 0)
{
var v = result.value
if (prefs.dot == "comma")
{
v = ""+v
var idp = v.indexOf('.')
if (idp >= 0)
v = v.substring(0,idp)+','+v.substring(idp+1)
}
document.getElementById('exp').value = v
document.getElementById('exp').style.width = "500px" // Restore
logAdd(expression, v, null)
return expset(false)
}
}
showErrors(expression, errors, evaluate)
showNesting(expression)
setExpression = expression
}
}


var rules = new Array(
new Array('NumberToExp', new Array('number') ),

new Array('CallNoParm', new Array( 'name', '(' , ')' ) ),
new Array('CallStart', new Array( 'name', '(' ) ),
//new Array('CallParm', new Array( 'call', 'exp', ',' ) ),
new Array('CallLast', new Array( 'call', 'exp', ')' ) ),
new Array('NameToExp', new Array( 'name' ) ),

new Array('Op', new Array( 'exp', 'op1', 'exp') ),

new Array('Unari1', new Array( 'start', 'op3', 'exp' ) ),
new Array('Unari1', new Array( '(', 'op3', 'exp' ) ),
new Array('Unari1', new Array( 'call', 'op3', 'exp' ) ),
new Array('Unari1', new Array( 'op1' , 'op3', 'exp' ) ),
new Array('Unari1', new Array( 'op2' , 'op3', 'exp' ) ),
new Array('Unari1', new Array( 'op3' , 'op3', 'exp' ) ),

new Array('BrExpBr', new Array( '(', 'exp', ')' ) ),
new Array('BrExpOpExpBr', new Array( '(', 'exp', 'op1', 'exp', ')' ) ),
new Array('BrExpOpExpBr', new Array( '(', 'exp', 'op2', 'exp', ')' ) ),
new Array('BrExpOpExpBr', new Array( '(', 'exp', 'op3', 'exp', ')' ) ),
new Array('Pct', new Array( 'exp', '%') ),
new Array('Fact', new Array( 'exp', '!') ),
new Array('Op', new Array( 'exp', 'op2', 'exp') ),
new Array('Op', new Array( 'exp', 'op3', 'exp') ),

new Array('last', new Array('?') )
)
function applyAllRules(tokens, errors)
{
// Add start token
var startToken = new Object()
startToken.type='start'
var t = new Array()
t[0] = startToken
append(tokens, t, 0, tokens.length-1)
tokens=t

var hasMatchingRule = true
while (hasMatchingRule && errors.length == 0)
{
var foundMatchingRule = false
for (var r in rules)
{
var rule = rules[r]
var handler = rule[0]
var types = rule[1]
var matchedPos = -1
for (var i=0; matchedPos < 0 && i<=tokens.length - types.length; i++)
{
var matched = true
for (var j = 0; matched && j < types.length; j++)
matched = (types[j] == tokens[i+j].type)
if (matched)
{
matchedPos = i
tokens = eval("rule"+handler+"(tokens, i, errors)")
}
}
if (matchedPos >= funcs)
{
foundMatchingRule = true
break
}
}
hasMatchingRule = foundMatchingRule
}
if (errors.length == 0 && tokens.length != 2)
analyzeFinalSyntaxErrors(tokens, errors)
return tokens[1]
}



// Find best matching error message
function analyzeFinalSyntaxErrors(tokens, errors)
{
var token
var message
for (var i=0; i<tokens.length-1; i++)
{
if (tokens[i].type == 'exp' && tokens[i+1].type == 'exp')
{
token = tokens[i+1]
message = "请给一个操作值"
break
}
if (tokens[i].type.indexOf('op')==0 && tokens[i+1].type.indexOf('op') == 0)
{
token = tokens[i+1]
message = "Wrong position of operator"
if (tokens[i].text=='*' && tokens[i+1].text=='*')
message +=". 到电脑中, 使用 2^3"
break
}
}

// Check parenthesis nesting
if (!token)
{
var brstack = new Array()
var brpos = -1
for (var i=0; !token && i<tokens.length; i++)
{
if (tokens[i].type == '(' || tokens[i].type == 'call')
brstack[++brpos] = i
else
if (tokens[i].type == ')')
{
if (--brpos)
{
token = tokens[i]
message = "括号不匹配"
}
}
}
if (!token && brpos >= 0)
{
token = tokens[brstack[brpos]]
if (token.type == '(')
message = "没有截止的括号"
else
message = "丢失结束函数调用"
}
}

// Check if ends with an op
if (!token && tokens[tokens.length-1].type.indexOf('op')==0)
{
token = tokens[tokens.length-1]
message = "公式不支持操作数"
}

if (!token)
{
token = tokens[1] // Default error position
message = "无效的语法表达"
}
var start
while (true)
{
if (token.start)
start = token.start
if (token.left)
token = token.left
else
break
}
var pos = token.start ? token.start : 0
addError(errors, message, pos, 1)
}
function append(source, target, sourceFromIndex, sourceToIndex)
{
for (var i=sourceFromIndex; i<=sourceToIndex; i++)
target[target.length] = source[i]
}
function ruleNumberToExp(tokens, pos, errors)
{
var oldToken = tokens[pos]
var newToken = new Object()
newToken.type='exp'
if (oldToken.text.substring(0,2).toLowerCase() == '0x')
newToken.value = parseInt(oldToken.text)
else
if (oldToken.text.indexOf('.') >= 0 || oldToken.text.indexOf('e') > 0)
newToken.value = parseFloat(oldToken.text)
else
if (oldToken.text.substring(0,2).toLowerCase() == '0b')
newToken.value = parseBinary(oldToken, errors)
else
newToken.value = parseInt(oldToken.text, 10) // Ignore octal
newToken.left = oldToken
tokens[pos] = newToken
return tokens
}
function ruleNameToExp(tokens, pos, errors)
{
var oldToken = tokens[pos]
var newToken = new Object()
newToken.type='exp'
var name = oldToken.text.toLowerCase()
var value = 0
if (name == 'pi')
value = Math.PI
else
if (name == 'e')
value = Math.E
else
if (variables[name])
{
var varval = variables[name]
var idp = varval.indexOf(',')
if (idp >= 0)
varval = varval.substring(0,idp)+'.'+varval.substring(idp+1)
if (varval.substring(0,2).toLowerCase() == '0x')
value  = parseInt(varval)
else
if (varval.indexOf('.') >= 0 || varval.indexOf('e') > 0)
value = parseFloat(varval)
else
if (varval.substring(0,2).toLowerCase() == '0b')
value = parseBinary(varval, errors)
else
value = parseInt(varval, 10)
}
else
{
addError(errors, "不支持的变量名 ["+name+"]", oldToken.start, oldToken.text.length)
}

newToken.value=value
newToken.left = oldToken
tokens[pos] = newToken
return tokens
}
function ruleBrExpBr(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos-1)

var newToken = new Object()
newToken.type='exp'
newToken.value=tokens[pos+1].value
newToken.left = tokens[pos+1]
newTokens[newTokens.length] = newToken

append(tokens, newTokens, pos+3, tokens.length-1)
return newTokens
}
function ruleBrExpOpExpBr(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos-1)
append(tokens, newTokens, pos+1, pos+3)
append(tokens, newTokens, pos+5, tokens.length-1)
return ruleOp(newTokens, pos, errors)
}
function ruleOp(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos-1)

var result = tokens[pos].value
var opToken = tokens[pos+1]
if (opToken.text == '+')
result += tokens[pos+2].value
if (opToken.text == '-')
result -= tokens[pos+2].value
if (opToken.text == '*')
result *= tokens[pos+2].value
if (opToken.text == '/')
{
result /= tokens[pos+2].value
if (result=="Infinity")
addError(errors, "除以零是不允许的", opToken.start, 1)
}
if (opToken.text == '^')
result = Math.pow(result, tokens[pos+2].value)
var newToken = new Object()
newToken.type='exp'
newToken.value=result
newTokens[newTokens.length] = newToken
newToken.left = opToken
opToken.left = tokens[pos]
opToken.right = tokens[pos+2]

append(tokens, newTokens, pos+3, tokens.length-1)
return newTokens
}
function rulePct(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos-1)

var result = tokens[pos].value / 100
var opToken = tokens[pos+1]
var newToken = new Object()
newToken.type='exp'
newToken.value=result
newTokens[newTokens.length] = newToken
newToken.left = opToken
opToken.left = tokens[pos]

append(tokens, newTokens, pos+2, tokens.length-1)
return newTokens
}
function ruleFact(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos-1)

fact = tokens[pos].value
if (fact <= 0 || fact != Math.floor(fact))
addError(errors, "阶乘只允许是正整数", tokens[pos].start, 1)
var result =  1;
for (var i=2; i<=fact; i++)
result *= i
var opToken = tokens[pos+1]
var newToken = new Object()
newToken.type='exp'
newToken.value=result
newTokens[newTokens.length] = newToken
newToken.left = opToken
opToken.left = tokens[pos]

append(tokens, newTokens, pos+2, tokens.length-1)
return newTokens
}
function ruleUnari1(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos)

var result = tokens[pos+2].value
var opToken = tokens[pos+1]
if (opToken.text == '-')
result = -result
var newToken = new Object()
newToken.type='exp'
newToken.value=result
newTokens[newTokens.length] = newToken
newToken.left = opToken
opToken.left = tokens[pos]
opToken.right = tokens[pos+2]

append(tokens, newTokens, pos+3, tokens.length-1)
return newTokens
}
function ruleCallNoParm(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos-1)
var nameToken = tokens[pos]
var callToken = new Object()
callToken.type='call'
callToken.name = nameToken.text.toLowerCase()
callToken.start = nameToken.start
callToken.left = nameToken
callToken.parms=new Array()
var callResult = processCall(callToken, errors)
newTokens[newTokens.length] = callResult
append(tokens, newTokens, pos+3, tokens.length-1)
return newTokens
}
function ruleCallStart(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos-1)
var nameToken = tokens[pos]
var newToken = new Object()
newToken.type = 'call'
newToken.name = nameToken.text.toLowerCase()
newToken.start = nameToken.start
newToken.left = nameToken
newToken.parms = new Array()
newTokens[newTokens.length] = newToken
append(tokens, newTokens, pos+2, tokens.length-1)
return newTokens
}
function ruleCallParm(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos)
var callToken = tokens[pos]
callToken.parms[callToken.parms.length]=tokens[pos+1]
append(tokens, newTokens, pos+3, tokens.length-1)
return newTokens
}
function ruleCallLast(tokens, pos, errors)
{
var newTokens = new Array()
append(tokens, newTokens, 0, pos-1)
var callToken = tokens[pos]
callToken.parms[callToken.parms.length]=tokens[pos+1]
var callResult = processCall(callToken, errors)
newTokens[newTokens.length] = callResult
append(tokens, newTokens, pos+3, tokens.length-1)
return newTokens
}

function validateFunctionParms(func, parms, errors, minParms, maxParms)
{
var ok = true
if (parms.length < minParms || parms.length > maxParms)
{
ok = false
if (minParms == maxParms)
addError(errors, "Function "+func.name+" expects "+minParms+(minParms == 1 ? " Parameter" : " Parameters"), func.start, func.name.length)
else
addError(errors, "Function "+func.name+" expects "+minParms+" to "+maxParms+" Parameters", func.start, func.name.length)
}
return ok
}
function processCall(token, errors)
{
var result = new Object()
result.type = 'exp'
result.left = token
var func = token.name
var parms = token.parms
if (func == 'ln')
func = 'log'

if (func == 'sqrt' || func=='abs' || func=='ceil' || func=='floor' || func=='log' || func=='round')
{
if (validateFunctionParms(token, parms, errors, 1, 1))
result.value = eval('Math.'+func+'('+parms[0].value+')')
}
else
if (func == 'sin' || func == 'cos'|| func == 'tan')
{
if (validateFunctionParms(token, parms, errors, 1, 1))
{
var v = parms[0].value
if (prefs.angle == 'deg')
v = v * Math.PI / 180
v = eval('Math.'+func+'('+v+')')
result.value = v
}
}
else
if (func == 'asin' || func == 'acos'|| func == 'atan')
{
if (validateFunctionParms(token, parms, errors, 1, 1))
{
var v = parms[0].value
v = eval('Math.'+func+'('+v+')')
if (prefs.angle == 'deg')
v = v * 180 / Math.PI
result.value = v
}
}
else
if (func == 'log10')
{
if (validateFunctionParms(token, parms, errors, 1, 1))
{
result.value = eval('Math.log('+parms[0].value+')/Math.log(10)')
}
}
else
if (func == 'hex')
{
if (validateFunctionParms(token, parms, errors, 1, 1))
{
result.value = parms[0].value
result.displayHex = true
}
}
else
if (func == 'bin')
{
if (validateFunctionParms(token, parms, errors, 1, 1))
{
result.value = parms[0].value
result.displayBin = true
}
}
else
addError(errors, "不支持的字符 ["+func+"]", token.start, func.length)

if (isNaN(result.value) || result.value == "Infinity")
addError(errors, "因功能为特定参数，未定义", token.start, func.length)

return result
}
function fixRoundingError(value)
{
var sv = ""+value
if (sv.indexOf('.') < 0)
return value
// TODO Handle "e" notation, leave only 12 digits after point
var s = sv.substring(sv.indexOf('.'))
var l = s.length
if (l < 10)
return value
var l5 = s.substring(l - 5)
var l5m1 = l5.substring(0, 4)
if (l5m1 == '9999')
{
var i9 = s.length-3
while (s.charAt(i9-1) == '9')
i9--
s = s.substring(0,i9+1)
var d = '.000000000000000000000000000000000'.substring(0,s.length-1)+'1'
var w = sv.substring(0, sv.indexOf('.'))
if (w == '')
w = '0'
var op = '+'
if (value < 0)
op = '-'
value = eval(w+op+'('+s+'+'+d+')')
}
else
if (l5m1 == '0000')
{
value = eval(sv.substring(0, sv.length-4))
}
return value
}
function hex(value)
{
var s = ""
var v = Math.round(value)
if (v < 0)
v = Math.abs(0x01000000000000 + v)
while (v != 0)
{
var p = v % 16
if (p < 0)
p = 16 + p
s = "0123456789abcdef".charAt(p) + s
v = Math.floor(v / 16)
}
if (s == "")
s = "0"
s = "0x"+s
return s
}
function bin(value)
{
var s = hex(value)
var bindig = ['0000','0001','0010','0011','0100','0101','0110','0111','1000','1001','1010','1011','1100','1101','1110','1111']
var hexdig = '0123456789abcdef'
var res = '0b'
for (var i = 2; i<s.length; i++)
res += bindig[hexdig.indexOf(s.charAt(i))]
return res
}
function parseBinary(token, errors)
{
var r = 0
var v = token.text // 0b0100
for (var i = 2; i<v.length; i++)
{
r *= 2
if (v.charAt(i) == '1')
r++
else
if (v.charAt(i) != '0')
{
addError(errors, "二进制值只能有数字0或1", token.start+i, 1)
return 0
}
}
return r
}


//
// Log (history) functions
//
var log = new Array()
function logAdd(exp, value, name)
{
if (exp != value)
{
if (log.length == 0 || log[log.length-1].expression != exp)
{
var entry = new Object()
entry.expression = exp
entry.result = value
if (name != null)
entry.name = name
log[log.length] = entry
logShow()
}
}
}
function logShow()
{
var str = ""
var opts = ""
if (log.length > 0)
{
str += "<span class='logtitle'>历史记录</span><br />"
opts += "<a href='javascript:logRemove()'>[清除选中记录]</a>&nbsp&nbsp;"
opts += "<a href='javascript:logCheckAll()'>[全选]</a>&nbsp;&nbsp;"
opts += "<a href='javascript:logClear()'>[清除所有记录]</a>&nbsp;&nbsp;"
opts += "<a href='javascript:copyLogToClipoard()' title='把全部记录以表格形式，复制到你的剪贴板中'>[复制所有记录]</a>"
opts += "<br /><br />"
str += opts
str += "<table border='0' width='720' cellpadding='2' cellspacing='1' bgcolor='#c0c0c0'>"

str += "<tr class='loghdr'><td>&nbsp;</td><td>公式</td><td>结果</td><td>名称</td></tr>"
for (var i=log.length-1; i>=0; i--)
{
var entry = log[i]
if (entry != null)
{
str += "<tr bgcolor='#ffffff'>"
str += "<td><input type='checkbox' id='log"+i+"' /></td>"
str += "<td><a title='复制到计算器中' href='javascript:logSet(&quot;"+entry.expression+"&quot;)'>"+entry.expression+"</a></td>"
str += "<td><a title='复制到计算器中' href='javascript:logSet(&quot;"+entry.result+"&quot;)'>"+entry.result+"</a></td>"
if (!entry.name)
str += "<td id='nameit"+i+"'><a href='javascript:nameit("+i+")' title='定义一个名称'>定义名称</a></td>"
else
str += "<td>"+entry.name+"</td>"
str += "</tr>"
}
}
str += "</table>"
str += opts
}
document.getElementById('log').innerHTML = str

if (prefs.saveHistory)
saveHistory();
}
function logSet(exp)
{
var v = document.getElementById('exp').value
var tv = v
while (tv.length > 0 && tv.charAt(tv.length-1) == ' ')
tv = tv.substring(0, tv.length-1)
if (tv.length > 0 && "+-*/^,(".indexOf(tv.charAt(tv.length-1)) >= 0)
exp = v+exp // Concat when ends with op
setexp(exp, false)
expFocus()
}
function logClear()
{
log = new Array()
logShow()
expFocus()
}
function logRemove()
{
var newLog = new Array()
for (var i=0; i<log.length; i++)
{
var chkbox = document.getElementById('log'+i)
if (chkbox && !chkbox.checked)
newLog[newLog.length] = log[i]
}
log = newLog
logShow()
expFocus()
}
function logCheckAll()
{
for (var i=0; i<log.length; i++)
{
var chkbox = document.getElementById('log'+i)
if (chkbox)
chkbox.checked = true
}
expFocus()
}

var nameitInd
function nameit(i)
{
document.getElementById('nameit').value = ""
var pos = position('nameit'+i)
setTimeout("document.getElementById('nameit').focus()", 200)
nameitInd = i
var form = document.getElementById('nameitf')
form.style.top = pos.top+"px"
form.style.left = (pos.left+40)+"px"
form.style.display='block'
}
function nameitset()
{
var name = document.getElementById('nameit').value
if (name.length > 0)
{
log[nameitInd].name=name
variables[name] =''+log[nameitInd].result
logShow()
}
}

//
// Button handlers
//
function btn(b)
{
var e = document.getElementById('exp').value
if (b == 'clear')
setexp('', false)
else
setexp(b+'('+e+')', true)

expFocus()
}

//
// Display functions
//
var expCharWidth
function charWidth()
{
if (expCharWidth)
return expCharWidth
var s = "8888888888"
document.getElementById('charws').innerHTML=s
expCharWidth = (document.getElementById('charwe').offsetLeft-document.getElementById('charws').offsetLeft) / s.length
document.getElementById('charws').innerHTML=''
return expCharWidth
}

function showErrors(expression, errors, showMessageText)
{
var errind = ""
errind += "<table border='0' cellpadding='0' cellspacing='0'><tr>"
errind += "<td><img src='/file/jisuanqi/s.gif' width='2' height='3' /></td>"
if (errors.length > 0)
{
var colErrors = new Array()
for (var i=0; i<errors.length; i++)
{
var error = errors[i]
for (var c=0; c<error.length; c++)
{
var pos = error.start+c
if (!colErrors[pos])
colErrors[pos] = error.message
}
}
var cw = charWidth()
for (var i=0; i<expression.length; i++)
{
errind += "<td width='"+cw+"'>"
if (colErrors[i])
errind += "<img src='/file/jisuanqi/errdec.gif' width='"+cw+"' height='3' title='"+colErrors[i]+"' />"
else
errind += "<img src='/file/jisuanqi/s.gif' width='"+cw+"' height='3' />"
errind += "</td>"
}
}
errind += "</tr></table>"
if (showMessageText && errors.length > 0)
{
var error = errors[0]
var cw = charWidth()

var pw = error.start*cw
errind += "<table border='0' cellpadding='0' cellspacing='0'><tr>"
errind += "<td><img src='/file/jisuanqi/s.gif' width='"+pw+"' height='6' /></td>"
errind += "<td><img src='/file/jisuanqi/errind.gif' width='10' height='6' /></td>"
errind += "</tr></table>"

errind += "<table border='0' cellpadding='2' cellspacing='0'><tr>"
var w = Math.max(400, pw+2*cw)
errind += "<td nowrap='true' width='"+w+"' class='errmsg'>"
errind += error.message
errind += "</td></tr></table>"
}
document.getElementById('errors').innerHTML = errind
}
function showNesting(expression)
{
var bkrind = ""
var cw = charWidth()
var maxLevel = 0
var level = 0
var levels = new Array()
for (var i=0; i<expression.length; i++)
{
var c = expression.charAt(i)
if ("([{".indexOf(c) >= 0)
{
if (++level > maxLevel)
maxLevel = level
levels[i] = level
}
else
if (")]}".indexOf(c) >= 0 && level > 0)
{
levels[i] = level
level--
}
else
levels[i] = level
}


if (maxLevel > 0)
{
bkrind += "<table border='0' cellpadding='0' cellspacing='0'>"
for (var level = maxLevel; level > 0; level--)
{
bkrind += "<tr><td><img src='/file/jisuanqi/s.gif' width='2' height='3' /></td>"
for (var i=0; i<expression.length; i++)
{
bkrind += "<td width='"+cw+"'>"
var img = "s"
if (levels[i] == level)
{
if (i == 0 || levels[i-1] < level)
img = "ns"
else
if (")]}".indexOf(expression.charAt(i)) >= 0)
img = "ne"
else
img = "nh"
}
else
if (levels[i] > level)
{
img = "nh"
}
else
if (levels[i] > 0 && "()[]{}".indexOf(expression.charAt(i)) >= 0)
{
img = "nv"
}

bkrind += "<img src='/file/jisuanqi/"+img+".gif' width='"+cw+"' height='3' />"

bkrind += "</td>"
}
bkrind += "</tr>"
}
bkrind += "</table>"
}

document.getElementById('nesting').innerHTML = bkrind
}

function copyLogToClipoard()
{
var text = "Expression\tValue\n"

for (var i=log.length-1; i>=0; i--)
{
var entry = log[i]
if (entry != null)
{
text += entry.expression+"\t"+entry.result+"\n"
}
}


if (window.clipboardData)
{
window.clipboardData.setData("Text", text)
}
else
{
alert('该功能目前只支持Internet Explorer')
}
}

// History management in cookie
var historyCookieName = "calcHistory"

function saveHistory()
{
var value = "";
var passedMaxSize = false

for (var i=log.length-1; i >=0 && !passedMaxSize;i--)
{
var entry = log[i]
if (entry != null)
{
var newValue = "//"+entry.expression+"=="+entry.result
if (entry.name)
newValue+="::"+entry.name
if (value.length+newValue.length<4096)
value=newValue+value
else
passedMaxSize=true
}
}
createCookie(historyCookieName, value, 365*10)
}

function readHistory()
{
if (prefs.saveHistory == false)
eraseCookie(historyCookieName)
else
{
var value = readCookie(historyCookieName)
log = new Array()

while (value != null && value.indexOf("//")>=0) {
var resultIndex = value.indexOf("==")
var nextExpIndex = value.indexOf("//", 2)
var exp = value.substring(2,resultIndex)
if (nextExpIndex != -1) {
var result = value.substring(resultIndex+2, nextExpIndex)
value = value.substring(nextExpIndex)
} else {
var result = value.substring(resultIndex+2)
value = ""
}
var nameIndex = result.indexOf("::")
var name = null
if (nameIndex>-1) {
name = result.substring(nameIndex+2)
result = result.substring(0, nameIndex)
variables[name] =''+result
}
logAdd(exp, result, name)
}
}
}

function position(id)
{
var pos = {left:0,top:0}
var item = document.getElementById(id)
while (item)
{
if (item.style.position == 'absolute')
break

pos.left += item.offsetLeft
pos.top  += item.offsetTop
item= item.offsetParent
}

return pos
}