Inicializações e chamada com ênfase no Parser
Vamos mostrar o início do programa, porém chamando apenas o Parser, para que as fases posteriores possam ser absorvidas com ampla compreensão desta fase fundamental:// Constantes e ARRAYS do CORE do parser e solve
var VARIABLES = [];
var FUNCOES = [];
FUNCOES["Exp"] = findExponential;
FUNCOES["Mul"] = findMultiplication;
FUNCOES["Div"] = findDivision;
FUNCOES["Sum"] = findSum;
FUNCOES["Sub"] = findSub;
FUNCOES["Abp"] = findOpenBrace;
FUNCOES["Fbp"] = findCloseBrace;
var textoConv = "";
// Processando a expressão
var res0 = parseVariables("17/2+19/3+1.01^10");
O array VARIABLES armazena as variáveis da expressão parseada, em itens cujos nomes são a junção de "V" com um número sequencial ajustado em campo de 2 numerais (V01, V02, ...), conforme mostrado nos esquemas dos posts anteriores.
O array FUNCOES armazena as funções que acham os operadores. E por que fazer assim, ao invés de utilizar os nomes das funções ? Para futuras automatizações e reduções de código.
O Parse
Nesta primeira abordagem, separamos uma chamada do Parse, para analisá-lo, antes de abordar o processo global de análise de prioridades, parse e resolução da expressão:// Processando a expressão
var res0 = parseVariables("17/2+19/3+1.01^10");
A observação digna de nota é a de que utilizamos o operador "^" para a exponenciação. No entanto, na resolução, utilizaremos a função Math.pow(), pois, como você poderá constatar, a expressão com operador dá um erro absurdo. experimente testar no debug de um navegador para comprovar este fato.
O código
Chamamos a função Parser de parseVariables, de forma que este código possa ser agregado a outros parsers de instruções, comandos e configurações sem risco de colisão de nomes, em seus programas futuros:function parseVariables(texto){
var tamTexto = texto.length;
var carctr = "";
var ind = 0;
var proxCarctr = "";
var S = "";
var Variable;
var SINAL, PROX_SINAL;
for(i=0;i<tamTexto;i++){
carctr = texto[i];
SINAL = "";
if( isOperator(carctr) ){
// Obtem próximo caracter
proxCarctr = texto[i+1];
if( isOperator(proxCarctr) ){
SINAL = proxCarctr;
i++;
} else {
SINAL = "";
if( PROX_SINAL == "-" ){
SINAL = PROX_SINAL;
PROX_SINAL = "";
}
}
// Verifica se o operador do caracter atual é "-" (subtração)
if( carctr == "-" ){
PROX_SINAL = carctr;
}
ind++;
// Lida com o sinal
S = SINAL.concat(S);
// Alimenta o array VARIABLES
VARIABLES[ind] = parseFloat(S);
Variable = adjustZero(ind.toString());
VARIABLES[Variable] = parseFloat(S);
// Refaz a expressão
if( carctr == "-" ) { carctr = "+"; }
textoConv = textoConv + Variable + carctr;
S = "";
// Númeral, e não operador
} else {
S = S + carctr;
}
}
// Último sinal armazenado em PROX_SINAL
if( PROX_SINAL == "-" ){
SINAL = PROX_SINAL;
PROX_SINAL = "";
}
S = SINAL.concat(S);
ind++;
VARIABLES[ind] = parseFloat(S);
Variable = adjustZero(ind.toString());
VARIABLES[Variable] = parseFloat(S);
textoConv = textoConv + Variable;
S = "";
return tamTexto;
}
Os fatores importantes a serem levados em conta para entender esta função são os seguintes:
- A expressão trabalhada aqui não contém parênteses. A cada loop da função solvExpression, obtemos uma expressão no nível mais interno dos parênteses restantes do loop anterior;
- Os caracteres numéricos são acumulados da esquerda para a direita, até que se encontre um operador aritmético;
- Encontrado um operador aritmético, é preciso verificar se ele está junto a um outro, fato que ocorre quando o próximo operando tiver um sinal negativo. Isto se dá nas seguintes combinações: "*-", "/-" e "^-". Se isto ocorrer, o sinal negativo será armazenado na variável SINAL, pois ele se refere ao próximo operando, e não a este. Então, o sinal é transferido para a variável PROX_SINAL. Na próxima passada, este sinal será lido desta variável;
- O sinal negativo é armazenado dentro do item, e o operador aritmético "-" é substituído pelo de soma ("+");
- A variável ind é incrementada a cada operador lido, pois sua presença indica que a leitura dos caracteres de um operando foi concluída;
- Os nomes dos índices das variáveis no array VARIABLES é a concatenação da letra "V" (de variável) com o conteúdo da variável ind ajustado em um campo de 2 zeros. Tal ajuste é feito pela função adjustZero.
Para compreender esta função, o diagrama do primeiro post desta série é muito útil. Para facilitar, vamos reproduzí-lo aqui:
Função adjustZero
// Ajusta um nome de variável num campo de número precedido de zeros
function adjustZero(texto){
texto = right1("000"+texto,2);
return "v"+texto
}
Esta função utiliza um truque muito simples. Coloca-se os zeros à esquerda do número, e depois coleta-se a string obtida a partir da direita. O ajuste é automético. Tal coleta pela direita é feita pela função right1.
Função right1
// Obtém o conteúdo À DIREITA DE UMA POSIÇÃO de uma string
function right1(texto,n){
return texto.substr(texto.length-n,n);
}
Como o javascript não disponibiliza a função right explícita, esta operação é feita pela função substr.
Conclusão
Resolver uma expressão é bem mais eficiente se representarmos seus operandos de uma forma estruturada, armazenada em array, com nomes de comprimentos iguais, para serem analisados pela próxima etapa de forma previsível.Veja no próximo post o código para resolução das expressões aritméticas.
Nenhum comentário:
Postar um comentário