Skip to content

Instantly share code, notes, and snippets.

@dimiro1
Created May 21, 2009 12:58
Show Gist options
  • Save dimiro1/115445 to your computer and use it in GitHub Desktop.
Save dimiro1/115445 to your computer and use it in GitHub Desktop.
/***************************************************************************
* Pequena implementação da calculadora "dc" do GNU/Linux *
* Copyright (C) 2009 by Claudemiro Alves Feitosa Neto *
* dimiro1@gmail.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licences> *
* *
***************************************************************************/
#include <stdio.h> /* rotinas de entrada e saida */
#include <stdlib.h> /* rotinas de alocação de memoria, ... */
#include <ctype.h> /* rotinas usadas no analisador lexico */
#include <string.h> /* rotinas usadas no analisador lexico */
#include <math.h> /* rotinas para calculos mais complexos */
#define STACK_SIZE 1024 /* tamanho maximo da pilha, uma melhor implementação da pilha seria usar listas ligadas */
#define TOKEN_SIZE 512 /* comprimento de um numero, poderia usar alocação dinamica */
FILE *dc_input; /* entrada de dados, em main é atribuido o valor da entrada padrao, que é o teclado */
int dc_stack_top; /* topo da pilha */
double dc_stack[STACK_SIZE]; /* um vetor que representa a pilha */
/* inicia a pilha */
void dc_start_stack ();
/* coloca numero na pilha e devolve o topo da pilha */
int dc_stack_push ( double num );
/* devolve o elemento da pilha */
double dc_stack_pop ();
/* imprime todos os elementos da pilha */
void dc_print_stack ();
/* imprime todos os elementos da pilha, removendo-os da pilha */
void dc_dangerous_print_stack ();
/* imprime o topo da pilha */
void dc_print_top ();
/* limpa a pilha */
void dc_clean_stack ();
/* verifica se a pilha esta vazia */
int dc_stack_is_empty ();
/* verifica se a pilha esta cheia */
int dc_stack_is_full ();
/* ciclo de leitura e avaliação das expressões */
void dc_read_eval_cycle ();
/* reporta um erro e sai do programa */
void dc_fatal ( char *message );
void dc_error ( char *message );
/* funções para a análise léxica */
void dc_next ();
void dc_save_and_next ();
void dc_clean_tokenval ();
/* variáveis para a análise lexica */
int dc_look; /* usado para nagevar letra por letra */
char dc_tokenval[TOKEN_SIZE]; /* usado para pegar os valores dos numeros */
/* inicio do programa */
int
main ( int argc, char **argv )
{
dc_input = stdin; /* faz com que a entrada seja a entrada padrao, ou seja o teclado */
dc_start_stack (); /* inicia a pilha */
dc_read_eval_cycle (); /* inicia a calculadora */
return EXIT_SUCCESS; /* programa terminou com sucesso */
}
/* analise lexica e avaliacao de expressoes, bem simples */
void
dc_read_eval_cycle ()
{
/* usada para para divisões, modulo ... */
double aux;
/* enquanto diferente de fim de arquivo,
no windows EOF é o mesmo que CTRL-Z, no GNU/Linux CTRL-D */
while ( ( dc_look = getc ( dc_input ) ) != EOF )
{
dc_clean_tokenval (); /* limpa o valor atual, do numero */
if ( dc_look == ' ' || dc_look == '\t' ) /* elimina espaços e tabs */
dc_next ();
/* testa se é um numero */
else if ( isdigit ( dc_look ) )
{
dc_save_and_next ();
/* continua ate encontrar algo diferente de um numero */
while ( isdigit ( dc_look ) )
dc_save_and_next ();
if ( dc_look == '.' )
{
dc_save_and_next ();
while ( isdigit ( dc_look ) )
dc_save_and_next ();
}
dc_stack_push ( atof ( dc_tokenval) ); /* coloca o numero na pilha */
}
/* operações da calculadora */
else if ( dc_look == '+' )
{
dc_stack_push ( dc_stack_pop () + dc_stack_pop () );
dc_next (); /* continua buscando digitos ou comandos */
}
else if ( dc_look == '-' )
{
aux = dc_stack_pop ();
dc_stack_push ( dc_stack_pop () + aux );
dc_next ();
}
else if ( dc_look == '*' )
{
dc_stack_push ( dc_stack_pop () * dc_stack_pop () );
dc_next ();
}
else if ( dc_look == '/' )
{
aux = dc_stack_pop ();
if ( aux == 0 )
dc_fatal ( "erro fatal, divisão por zero." );
dc_stack_push ( dc_stack_pop () / aux );
dc_next ();
}
else if ( dc_look == '^' ) /* exponenciação */
{
dc_stack_push ( pow ( dc_stack_pop (), dc_stack_pop () ) );
dc_next ();
}
else if ( dc_look == 'v' ) /* raiz quadrada, cuidado ao usar essa função pois ela é uma funçao unária,
ela opera sobre o topo da pilha */
{
dc_stack_push ( sqrt ( dc_stack_pop () ) );
dc_next ();
}
else if ( dc_look == '%' ) /* resto da divisão */
{
aux = dc_stack_pop ();
if ( aux == 0 )
dc_fatal ( "erro fatal, divisão por zero." );
dc_stack_push ( (int) dc_stack_pop () % (int) aux ); /* a operação de modulo so aceita inteiros */
dc_next ();
}
else if ( dc_look == 'p' ) /* imprime o topo da pilha */
{
dc_print_top ();
dc_next ();
}
else if ( dc_look == 'f' ) /* mostra todos os valores da pilha, sem os alterar */
{
dc_print_stack ();
dc_next ();
}
else if ( dc_look == 'n' ) /* mostra todos os valores da pilha, eliminando-os */
{
dc_dangerous_print_stack ();
dc_next ();
}
else if ( dc_look == 'c' ) /* limpa a pilha */
{
dc_clean_stack ();
dc_next ();
}
else if ( dc_look == 'd' ) /* duplica o topo da pilha */
{
dc_stack_push ( dc_stack[dc_stack_top]);
dc_next ();
}
else if ( dc_look == 'q' ) /* sai normalmente do programa */
exit ( 0 );
else
dc_error ( "valor não numerico." );
}
}
/* funções do analisador lexico */
void
dc_next ()
{
dc_look = getc ( dc_input );
}
void
dc_save_and_next ()
{
char s[10];
sprintf ( s, "%c", dc_look );
strcat ( dc_tokenval, s );
dc_next ();
}
void
dc_clean_tokenval ()
{
strcpy ( dc_tokenval, "" );
}
/* fim funções do analisador lexico */
/* funções que operam sobre a pilha */
void
dc_start_stack ()
{
dc_stack_top = -1;
}
int
dc_stack_push ( double num )
{
if ( dc_stack_is_full () )
dc_error ( "pilha cheia." );
int position = dc_stack_top;
dc_stack[++dc_stack_top] = num;
return position;
}
double
dc_stack_pop ()
{
if ( dc_stack_is_empty () )
dc_error ( "pilha vazia." );
return dc_stack[dc_stack_top--];
}
void
dc_print_top ()
{
if ( dc_stack_is_empty () )
dc_error ( "pilha vazia." );
else
printf ( "%g\n", dc_stack[dc_stack_top] );
}
void
dc_print_stack ()
{
int i;
if ( dc_stack_is_empty () )
dc_error ( "pilha vazia." );
else
for ( i = dc_stack_top; i >= 0; i-- )
printf ( "%g\n", dc_stack[i] );
}
void
dc_dangerous_print_stack ()
{
while ( !dc_stack_is_empty () ) /* enquanto a pilha não for vazia */
printf ( "%g\n", dc_stack_pop () );
}
int
dc_stack_is_empty ()
{
return dc_stack_top == -1; /* caso seja -1 a pilha esta vazia */
}
int
dc_stack_is_full ()
{
return dc_stack_top == STACK_SIZE; /* esta cheia? */
}
void
dc_clean_stack ()
{
dc_stack_top = -1; /* simples assim, para limpar a pilha a unica coisa que faço é retornar dc_stack_top para -1 */
}
/* fim funções que operam sobre a pilha */
/* funções para reportar erros */
void
dc_error ( char *message )
{
fprintf ( stderr, "%s\n", message ); /* envia erro para a saida de erro padrão, geralmente é o monitor */
}
void
dc_fatal ( char *message )
{
dc_error ( message );
exit ( 1 );
}
/* fim funções para reportar erros */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment