Desejo criar um aplicativo simples de prova de conceito (REPL) que use um número e depois processe comandos nesse número.
Exemplo: eu começo com 1. Então eu escrevo " add 2
", ele me fornece 3. Então eu escrevo " multiply 7
", ele me fornece 21. Então eu quero saber se é primo, então eu escrevo " is prime
" (no número atual - 21), isso me dá falso. " is odd
" me daria verdade. E assim por diante.
Agora, para um aplicativo simples com poucos comandos, até um simples switch
seria o processamento dos comandos. Mas se eu quiser extensibilidade, como precisaria implementar a funcionalidade? Eu uso o padrão de comando? Construo um analisador / intérprete simples para o idioma? E se eu quiser comandos mais complexos, como " multiply 5 until >200
"? Qual seria uma maneira fácil de estendê-lo (adicionar novos comandos) sem recompilar?
Edit: para esclarecer algumas coisas, meu objetivo final não seria fazer algo semelhante ao WolframAlpha, mas sim um processador de lista (de números). Mas quero começar devagar no início (em números únicos).
Estou pensando em algo semelhante ao modo como alguém usaria o Haskell para processar listas, mas uma versão muito simples. Eu estou querendo saber se algo como o padrão de comando (ou equivalente) seria suficiente, ou se eu tenho que criar uma nova minilinguagem e um analisador para que ele atinja meus objetivos?
Edit2: Obrigado por todas as respostas, todas têm sido muito úteis para mim, mas o Emmad Kareem me ajudou mais, por isso vou escolher como resposta. Obrigado novamente!
fonte
Respostas:
Isso soa como um intérprete. Parece que você está mais preocupado com a implementação do que com a funcionalidade detalhada (só estou supondo aqui). Este projeto, se estendido, não é uma tarefa trivial. Certifique-se de estudar o escopo claramente, pois isso requer uma abordagem de engenharia e não uma abordagem de desenvolvimento ad-hoc para obter um produto confiável, em vez de um produto com 1000 correções que às vezes funciona apenas.
Decida uma sintaxe e esteja pronto para analisá-la e executar as verificações de sintaxe necessárias. Este link pode ajudá-lo com isso: Crie seu próprio analisador .
Dê uma olhada: neste tópico, pois aborda diferentes aspectos do trabalho, também existem bons links que podem ajudá-lo (especialmente a resposta do RMK): Criando um intérprete de idiomas . Você pode querer ver um exemplo de um projeto interessante que é um pouco semelhante em: Calculadora científica programável final . Você pode encontrar o código-fonte e o programa de trabalho para um interpretador de C # da linha de comando aqui Implementação da linha de comando do C # -Made-for-Teaching . Usar o compilador para executar tarefas complexas para você, como análise e digitação de variáveis, etc., pode ser uma maneira inteligente de escapar das complexidades de escrever tudo isso sozinho. Além disso, existe a opção Mono, que fornece um recurso de shell charp que você pode dar uma olhada em: CsharpRepl .
fonte
A menos que você esteja especificamente interessado em escrever o analisador real para si mesmo, sugiro dar uma olhada em uma das estruturas de gerador de analisador. Para C você tem YACC ou Bison , mas deve haver outras alternativas para outros idiomas, se preferir.
Isso elimina as complexidades de analisar gramáticas complexas e permite que você se concentre na tarefa que deseja executar. É claro que isso pode ser um exagero para a gramática sugerida na pergunta, mas como você menciona ter a opção de expandir para uma gramática mais complexa posteriormente, vale a pena obter alguma inspiração dessas estruturas.
fonte
O que você está descrevendo está muito próximo de uma linguagem de pilha .
Por exemplo, no Fator, o que você descreve seria feito como
Ou você pode definir suas próprias palavras e depois usá-las, como
Com essas definições, o exemplo acima se torna
Normalmente, os idiomas de pilha são fáceis de analisar porque usam palavras únicas separadas por espaço. Eu sugiro que você dê uma olhada no Factor - pode ser exatamente o que você deseja. Deve ser fácil definir as palavras que fazem o processamento necessário.
Edição : Se você realmente deseja criar uma linguagem semelhante, sugiro que você jogue com uma delas de qualquer maneira. A análise de uma linguagem de pilha é trivial - você divide em espaços em branco, e uma implementação ingênua de processamento é fácil: você só precisa cuidar do que acontece em uma pilha.
fonte
Você não deveria. A extensibilidade cria muita complexidade para pouquíssimos ganhos. Dito isto, você precisará fornecer um gancho para o estado existente. Uma maneira de ver o estado, modificar o estado e fornecer um mecanismo para retornar outros resultados (imprimir na tela). Você precisará de uma maneira do código principal descobrir módulos, carregá-los e enviar comandos para eles.
Você pode, mas provavelmente não é apropriado.
Você não vai pegar a entrada inteira e enviá-la para processamento, mas, em vez disso, analisa a entrada, despacha para o manipulador correto e deixa que ela faça seu trabalho. O comando não varia nessa comunicação; então nenhum padrão de comando.
Você precisará de algo para lidar com a quebra da entrada em tokens. Para uma solução extensível, você provavelmente não fará muito mais. Para uma solução bem definida, ter uma árvore de análise completa fornecerá melhor desempenho, manipulação de erros e capacidade de depuração.
Talvez você deva procurar a linguagem LISt Processing . A justaposição de código e dados deve se encaixar bem no que você descreve.
fonte