He encontrado un programa llamado Anagram (
http://www.parsifalsoft.com/) que permite crear el parser de la calculadora de manera automatica. Primero definimos que secuencias debe entender la calculadora, luego verificamos con una especie de debugger y por ultimo generamos el .c y el .h .
Es menos eficiente que el parser propuesto BrunoF, pero seguramente es más robusto y sencillo de modificar.
Este tipo de programas se usan para generar parsers más complejos que el de una calculadora y puede que el código no quepa en los PIC16/18, pero por lo menos creo que merece la pena tenerlo en cuenta.
Por ejemplo si se pretende añadir a la calculadora las matrices, puede ser complejo modificar el parser actual para que reconozca correctamente sentencias como [1,2;1,2] o [[1,2][1,2]] o puede tener bugs dificiles de detectar.
Este ejemplo que muestro de una calculadora viene con el programa. El .c generado son 1000 lineas y el .h 60 y permite realizar estas operaciones:
/* test.ffc - test file for ffcalc.syn grammar */
(156.7-8.2+1.5)/3 - 7*7
F=32
C = (5/9)*(F-32)
a=3
a= 10*(10*(10*(a+7)))
m=3
b=9
x=7
y = m*x + b
Este es el codigo que describe el parser:
{/* FOUR FUNCTION CALCULATOR: FFCALC.SYN */}
// -- CONFIGURATION SECTION ----------------------------
[
default token type = double
disregard white space
lexeme { real}
]
// -- FOUR FUNCTION CALCULATOR -------------------------
(void) calculator $
-> [calculation?, '\n']..., eof
(void) calculation
-> expression:x =printf("%g\n",x);
-> name:n, '=', expression:x ={
printf("%c = %g\n",n+'A',value[n]=x);}
-> error
expression
-> term
-> expression:x, '+', term:t = x+t;
-> expression:x, '-', term:t = x-t;
term
-> factor
-> term:t, '*', factor:f = t*f;
-> term:t, '/', factor:f = t/f;
factor
-> name:n = value[n];
-> real
-> '(', expression:x, ')' = x;
-> '-', factor:f = -f;
// -- LEXICAL UNITS ------------------------------------
digit = '0-9'
eof = -1
(void) white space
-> ' ' + '\t' + '\r' + '\f' + '\v'
-> "/*", ~eof?..., "*/"
(int) name
-> 'a-z' + 'A-Z':c = c-'A';
real
-> integer part:i, '.', fraction part:f = i+f;
-> integer part, '.'?
-> '.', fraction part:f = f;
integer part
-> digit:d = d-'0';
-> integer part:x, digit:d = 10*x + d-'0';
fraction part
-> digit:d =(d-'0')/10.;
-> digit:d, fraction part:f =(d-'0' + f)/10.;
{ /* -- EMBEDDED C ---------------------------------- */
double value[64]; /* registers */
int main(void) {
ffcalc();
return 0;
}
} /* -- END OF EMBEDDED C ----------------------------*/