Código fonte fornecido por Toco.
A resolução de expressões matemáticas contidas numa string pode ser resolvida em ABAP conforme exposto.
REPORT YRESFORM. PARAMETERS: PFORM(255). DATA FRES TYPE F. PERFORM RESOLVER_FORMULAEXP USING PFORM FRES 9. WRITE: / 'Resultado: ', FRES. FORM RESOLVER_FORMULAEXP USING PFORMULA PRESULTADO PNRDEC. * Operadores válidos em pformula. CONSTANTS VC_OPERADORES(5) VALUE '^*/+-'. DATA: BEGIN OF ITAB_FORMULA OCCURS 0, OPERADOR, VALOR(16) TYPE P DECIMALS 9, END OF ITAB_FORMULA. DATA: VL_CARACTER, "Caracter da string pformula. VL_POS TYPE I, "Posição da string pformula. VL_VALOR(40), "Contém um operando da formula. VL_VALOR1(16) TYPE P DECIMALS 9, "1º valor de uma operação. VL_OPERADOR, "Operador matemático. VL_VALOR2(16) TYPE P DECIMALS 9, "2º valor de uma operação. VL_POSCARACTER TYPE I, "Posição da varredura de string. VL_FORMULA2(255), "Variável auxiliar. VL_VALORAUX(16) TYPE P DECIMALS 9, "Variável auxiliar. VL_STRAUX(255), "Variável auxiliar. VL_LENSTR TYPE P. "Tamanho em carac. de pformula. ************************************************************************ * Preenche a tabela itab_formula com valores e operadores. * Suponhamos a seguinte formula: 4*6/2+1 * A tabela itab_formula conterá quatro registros da seguinte forma. * * 4,0000000000 + * 6,0000000000 / * 2,0000000000 + * 1,0000000000 * * Atenção: A tabela é preenchida até ser encontrada o final da fórmula * ou um fecha parênteses ")". ************************************************************************ VL_LENSTR = STRLEN( PFORMULA ). DO VL_LENSTR TIMES. VL_POS = SY-INDEX - 1. VL_CARACTER = PFORMULA+VL_POS(1). " Encerra operação quando um fecha parênteses for encontrado. IF VL_CARACTER = ')'. EXIT. ENDIF. * Quando um abre parênteses for encontrado, processa tudo dentro dos * parênteses chamando novamente a função de cálculo de fórmula. IF VL_CARACTER = '('. CLEAR VL_VALOR. VL_POS = VL_POS + 1. VL_FORMULA2 = PFORMULA+VL_POS. PERFORM RESOLVER_FORMULAEXP USING VL_FORMULA2 VL_VALORAUX PNRDEC. * Altera pformula para continuar sendo avaliada. * O valor da avaliação dos parênteses (vl_valorAux) é colocado na variá- * vel valor para que possa ser considerado. VL_POS = VL_POS - 1. IF VL_POS <> 0. VL_STRAUX = PFORMULA(VL_POS). ELSE. CLEAR VL_STRAUX. ENDIF. VL_VALOR = VL_VALORAUX. "Considera resultado do parênteses. CONCATENATE VL_STRAUX VL_FORMULA2 INTO PFORMULA. VL_CARACTER = PFORMULA+VL_POS(1). ENDIF. * O Fecha parênteses no If serve quando estamos no final de uma expres- * são entre parênteses, sendo que o último valor deve ser considerado. IF VC_OPERADORES CA VL_CARACTER OR VL_CARACTER = ')'. " Insere valor e operador na tabela interna. CLEAR ITAB_FORMULA. IF VL_CARACTER <> ')'. ITAB_FORMULA-OPERADOR = VL_CARACTER. ELSE. "O fecha parênteses deve ser processado novamente. CONCATENATE '0' PFORMULA INTO PFORMULA. ENDIF. ITAB_FORMULA-VALOR = VL_VALOR. APPEND ITAB_FORMULA. CLEAR VL_VALOR. ELSE. CONCATENATE VL_VALOR VL_CARACTER INTO VL_VALOR. ENDIF. ENDDO. IF NOT VL_VALOR IS INITIAL. CLEAR ITAB_FORMULA. ITAB_FORMULA-VALOR = VL_VALOR. APPEND ITAB_FORMULA. ENDIF. ************************************************************************ * Realiza cálculo dos dados da tabela itab_formula. * ************************************************************************ * Elimina parte da string que já foi processada. VL_POS = VL_POS + 1. IF VL_POS <> VL_LENSTR. PFORMULA = PFORMULA+VL_POS. ELSE. CLEAR PFORMULA. ENDIF. * Resolve fórmula contina na tabela itab_formula, considerando preceden- * cia de operadores. VL_POSCARACTER = 0. WHILE VL_POSCARACTER < 5. VL_CARACTER = VC_OPERADORES+VL_POSCARACTER(1). READ TABLE ITAB_FORMULA WITH KEY OPERADOR = VL_CARACTER. "Se trata-se de operador * OU +, a pesquisa deve ser diferente. IF VL_CARACTER = '*'. " Procura '*' ou '/'. O que encontrar primeiro é o que vale. IF SY-SUBRC = 0. VL_POS = SY-TABIX. READ TABLE ITAB_FORMULA WITH KEY OPERADOR = '/'. IF ( SY-SUBRC = 0 AND SY-TABIX > VL_POS ) OR SY-SUBRC <> 0. READ TABLE ITAB_FORMULA INDEX VL_POS. ENDIF. ELSE. READ TABLE ITAB_FORMULA WITH KEY OPERADOR = '-'. ENDIF. ELSEIF VL_CARACTER = '+'. " Procura '+' ou '-'. O que encontrar primeiro é o que vale. IF SY-SUBRC = 0. VL_POS = SY-TABIX. READ TABLE ITAB_FORMULA WITH KEY OPERADOR = '-'. IF ( SY-SUBRC = 0 AND SY-TABIX > VL_POS ) OR SY-SUBRC <> 0. READ TABLE ITAB_FORMULA INDEX VL_POS. ENDIF. ELSE. READ TABLE ITAB_FORMULA WITH KEY OPERADOR = '-'. ENDIF. ENDIF. IF SY-SUBRC = 0. "Realiza operação deste item com seu sucessor. "Utiliza vl_pos para armazenar nº do registro da tabela interna+1. VL_POS = SY-TABIX + 1. VL_VALOR1 = ITAB_FORMULA-VALOR. VL_OPERADOR = ITAB_FORMULA-OPERADOR. READ TABLE ITAB_FORMULA INDEX VL_POS. VL_VALOR2 = ITAB_FORMULA-VALOR. CASE VL_OPERADOR. WHEN '^'. ITAB_FORMULA-VALOR = VL_VALOR1 ** VL_VALOR2. WHEN '*'. ITAB_FORMULA-VALOR = VL_VALOR1 * VL_VALOR2. WHEN '/'. IF VL_VALOR2 <> 0. ITAB_FORMULA-VALOR = VL_VALOR1 / VL_VALOR2. ELSE. MESSAGE I010(ZSAPMZS01). CLEAR PRESULTADO. EXIT. ENDIF. WHEN '+'. ITAB_FORMULA-VALOR = VL_VALOR1 + VL_VALOR2. WHEN '-'. ITAB_FORMULA-VALOR = VL_VALOR1 - VL_VALOR2. ENDCASE. * Efetua arredondamento do resultado conforme PNRDEC. ITAB_FORMULA-VALOR = ITAB_FORMULA-VALOR * ( 10 ** PNRDEC ). ITAB_FORMULA-VALOR = TRUNC( ITAB_FORMULA-VALOR ). ITAB_FORMULA-VALOR = ITAB_FORMULA-VALOR / ( 10 ** PNRDEC ). MODIFY ITAB_FORMULA INDEX VL_POS. VL_POS = VL_POS - 1. DELETE ITAB_FORMULA INDEX VL_POS. ELSE. VL_POSCARACTER = VL_POSCARACTER + 1. ENDIF. ENDWHILE. PRESULTADO = ITAB_FORMULA-VALOR. ENDFORM. " RESOLVER_FORMULAEXP