Quiero hacer una aplicación simple de prueba de concepto (REPL) que tome un número y luego procese comandos en ese número.
Ejemplo: empiezo con 1. Luego escribo " add 2
", me da 3. Luego escribo " multiply 7
", me da 21. Entonces quiero saber si es primo, entonces escribo " is prime
" (en el número actual - 21), me da falso. " is odd
" me daría la verdad. Y así.
Ahora, para una aplicación simple con pocos comandos, incluso un simple switch
serviría para procesar los comandos. Pero si quiero extensibilidad, ¿cómo necesitaría implementar la funcionalidad? ¿Utilizo el patrón de comando? ¿Construyo un analizador / intérprete simple para el idioma? ¿Qué sucede si quiero comandos más complejos, como " multiply 5 until >200
"? ¿Cuál sería una manera fácil de extenderlo (agregar nuevos comandos) sin volver a compilar?
Editar: para aclarar algunas cosas, mi objetivo final no sería hacer algo similar a WolframAlpha, sino más bien un procesador de listas (de números). Pero quiero comenzar lentamente al principio (en números individuales).
Tengo en mente algo similar a la forma en que uno usaría Haskell para procesar listas, pero una versión muy simple. Me pregunto si algo como el patrón de comando (o equivalente) sería suficiente, o si tengo que hacer un nuevo mini-idioma y un analizador para lograr mis objetivos.
Edit2: Gracias por todas las respuestas, todas me han sido de gran ayuda, pero Emmad Kareem me ha ayudado más, así que la elegiré como respuesta. ¡Gracias de nuevo!
fuente
Respuestas:
Esto suena como un intérprete. Parece que le preocupa más la implementación que la funcionalidad detallada (solo supongo que aquí). Este proyecto si se extiende no es una tarea trivial. Asegúrese de estudiar el alcance claramente, ya que esto requiere un enfoque de ingeniería y no un enfoque de desarrollo ad-hoc para obtener un producto confiable en lugar de un producto con 1000 parches que a veces solo funciona.
Decida una sintaxis y esté listo para analizarla y realizar las comprobaciones de sintaxis necesarias. Este enlace puede ayudarlo con esto: cree su propio analizador .
Eche un vistazo a este tema, ya que toca diferentes aspectos del trabajo, también hay buenos enlaces que pueden ayudarlo (especialmente la respuesta de RMK): Creación de un intérprete de idiomas . Es posible que desee ver un ejemplo de un proyecto atractivo que sea algo similar en: Ultimate Programmable Scientific Calculator . Puede encontrar el código fuente y el programa de trabajo para un intérprete de línea de comandos C # aquí Command-Line-Implementation-of-C # -Made-for-Teaching . Usar el compilador para hacer las tareas complejas para usted, como el análisis y la escritura de variables, etc., puede ser una forma inteligente de escapar de las complejidades de escribir todo esto usted mismo. Además, existe la opción Mono que proporciona una función de shell charp que quizás desee ver: CsharpRepl .
fuente
A menos que esté específicamente interesado en escribir el analizador real para usted, le sugiero que eche un vistazo a uno de los marcos del generador de analizadores. Para C tienes YACC o Bison , pero debería haber otras alternativas para otros idiomas si lo prefieres.
Esto elimina la complejidad de analizar gramáticas complejas y le permite concentrarse en la tarea que desea hacer. Por supuesto, esto puede ser excesivo para la gramática que sugiere en la pregunta, pero dado que menciona tener la opción de expandirse a una gramática más compleja más tarde, al menos vale la pena obtener algo de inspiración de estos marcos.
fuente
Lo que está describiendo está muy cerca de un lenguaje de pila .
Por ejemplo, en Factor, lo que describe se haría como
O podría definir sus propias palabras y luego usarlas, como
Con estas definiciones, el ejemplo anterior se convierte en
Por lo general, los idiomas de pila son triviales para analizar porque usan palabras individuales separadas por espacios. Le sugiero que eche un vistazo a Factor: puede ser exactamente lo que desea. Debería ser fácil definir las palabras que realizan el procesamiento que necesita.
EDITAR : Si realmente quieres diseñar un lenguaje similar, te sugiero que juegues con uno de ellos de todos modos. Analizar un lenguaje de pila es trivial: se divide en espacios en blanco, y una implementación ingenua del procesamiento es fácil: solo tiene que ocuparse de lo que sucede en una pila.
fuente
No deberías La extensibilidad crea mucha complejidad para muy poca ganancia. Dicho esto, deberá proporcionar un enlace al estado existente. Una forma de ver el estado, modificar el estado y proporcionar un mecanismo para devolver otros resultados (imprimir en pantalla). Necesitará una forma para que el código central descubra los módulos, los cargue y les envíe comandos.
Puedes, pero es probable que no sea apropiado.
No va a tomar toda la entrada y enviarla para su procesamiento, sino que analiza la entrada, la envía al controlador correcto y deja que haga su trabajo. El comando no varía en esa comunicación; entonces no hay patrón de comando.
Necesitará algo para manejar dividir la entrada en tokens. Para una solución extensible, probablemente no harás mucho más. Para una solución bien definida, tener un árbol de análisis completo proporcionará un mejor rendimiento, manejo de errores y capacidad de depuración.
Entonces quizás deberías buscar en el lenguaje de procesamiento de LISt . La yuxtaposición de código y datos debe encajar bien con lo que usted describe.
fuente