四則演算するテスト

前書いたスタックを使って

前々から気になってた逆ポーランド記法に変換して処理する四則演算器書いた。

 

infix2postfix.h

#include <stdio.h>
#include <stdlib.h>
#include "stack.h"

enum Priority {NIL, LOW, MIDDLE, HIGH,};

static void check_argument(char **string, stack *st)
{
    make_stack(for_string);
    char *tmp;
    tmp = (char *)malloc(sizeof(char));
    if(tmp == NULL){
        break_stack(*st);
        return;
    }
    *tmp = ' ';
    push_stack(st, tmp);
    while(1){
        tmp = (char *)malloc(sizeof(char));
        if(tmp == NULL){
            break_stack(*st);
            return;
        }
        if(**string == '.' || **string == '_' || **string == '@' || ('A' <= **string && **string <= 'Z') || ('a' <= **string && **string <= 'z')){
            *tmp = **string;
            push_stack(&for_string, tmp);
            ++(*string);
        }else if(**string == '('){

        }else{
            while(top_stack(&for_string) != NULL){
                push_stack(st,top_stack(&for_string));
                pop_stack(&for_string);
            }
            --(*string);
            return;
        }

    }
}

static int check_constant(char **string, stack *st)
{
    make_stack(for_string);
    char *tmp;
    tmp = (char *)malloc(sizeof(char));
    if(tmp == NULL){
        break_stack(*st);
        return;
    }
    *tmp = ' ';
    push_stack(st, tmp);
    while(1){
        tmp = (char *)malloc(sizeof(char));
        if(tmp == NULL){
            break_stack(*st);
            return;
        }
        if('0' <= **string && **string <= '9'){
            *tmp = **string;
            push_stack(&for_string, tmp);
            ++(*string);
        }else{
            while(top_stack(&for_string) != NULL){
                push_stack(st,top_stack(&for_string));
                pop_stack(&for_string);
            }
            --(*string);
            return;
        }
    }
}  
   
static int ret_prio(char str)
{
    enum Priority;
    if(str == '(' || str == ')')return NIL;
    if(str == '+' || str == '-')return LOW;
    if(str == '*' || str == '/' || str == '%')return MIDDLE;
    if( ('a' <= str && str <= 'z') || ('A' <= str &&  str <= 'Z') || str == ' ' || str == '_' || str == '@' || str == '.' || ('0' <= str && str <= '9'))return HIGH;
    return -1;
}

char *convert(char *formula,char for_convert[])
{
    int i = 0;
    make_stack(st);
    while(*formula != '\0'){
        char *tmp;
        while(*formula == ' ') ++formula;
        if(*formula == '('){
            tmp = (char *)malloc(sizeof(char));
            *tmp = *formula;
            push_stack(&st, (void *)tmp);
        }else if(*formula == ')'){
            while(*(char *)top_stack(&st) != '('){
                if(top_stack(&st) != NULL){
                    *(for_convert+i) = *(char*)top_stack(&st);
                    ++i;
                    free(top_stack(&st));
                    pop_stack(&st);
                }else{
                    puts("error");
                    break_stack(st);
                    return NULL;
                }

            }
            pop_stack(&st);
        }else if( ('a' <= *formula && *formula <= 'z') || ('A' <= *formula && *formula <= 'Z') || *formula == '_' || *formula == '@' || *formula == '.'){
            check_argument(&formula, &st);
        }else if('0' <= *formula && *formula <= '9'){
            check_constant(&formula, &st);
        }else if(*formula == '+' || *formula == '-' || *formula == '*' || *formula == '/' || *formula == '%'){
            while(top_stack(&st) != NULL && ret_prio(*formula) <= ret_prio(*(char *)top_stack(&st))){
                *(for_convert+i) = *(char*)top_stack(&st);
                ++i;
                free(top_stack(&st));
                pop_stack(&st);
            }
            tmp = (char *)malloc(sizeof(char));
            if(tmp == NULL){
                break_stack(st);
                return NULL;
            }
            *tmp = ' ';
            push_stack(&st, (void *)tmp);
            tmp = (char *)malloc(sizeof(char));
            if(tmp == NULL){
                break_stack(st);
                return NULL;
            }
            *tmp = *formula;
            push_stack(&st, (void *)tmp);
        }else{
            break_stack(st);
            return NULL;
        }
        ++formula;
    }
    while(top_stack(&st) != NULL){
        if(*(char*)top_stack(&st) == '('){
            int m;
            puts("error");
            break_stack(st);
            for(m=0;m!=i;++m){
                *(for_convert+m)='\0';
            }
            return NULL;
        }
        *(for_convert+i) = *(char*)top_stack(&st);
        ++i;
        free(top_stack(&st));
        pop_stack(&st);
    }
    break_stack(st);
    return 0;
}

 

eval4rules.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include "stack.h"

double evaluation(char *formula,jmp_buf for_error){
    make_stack(st);
    double Ret;
    char p[20]="";
    while(*formula != '\0'){
        const char *var_for_atoi;
        if('0' <= *formula && *formula <= '9'){
            double *num = (double*)malloc(sizeof(double));
            if(num == NULL){
                break_stack(st);
                longjmp(for_error,-2);
            }
            while('0' <= *formula && *formula <= '9'){
                char chr[2] = "";
        chr[0] = *formula;
                strcat(p,chr);
                ++formula;
            }
            var_for_atoi = p;
            *num = atof(var_for_atoi);
            push_stack(&st,num);
            strcpy(p,"");
        }else if(*formula == '+' || *formula == '-' || *formula == '*' || *formula == '/'){
            double *num = (double*)malloc(sizeof(double));
            if(num == NULL){
                break_stack(st);
                longjmp(for_error,-2);
            }
            double a,b;
            if(top_stack(&st) == NULL){
                break_stack(st);
                longjmp(for_error,-1);
            }else{
                a = *(double*)top_stack(&st);
                free(top_stack(&st));
                pop_stack(&st);
            }
            if(top_stack(&st) == NULL){
                break_stack(st);
                longjmp(for_error,-1);
            }else{
                b = *(double*)top_stack(&st);
                free(top_stack(&st));
                pop_stack(&st);
            }
            switch(*formula){
            case '+':
                *num = a+b;
                break;

            case '-':
                *num = b-a;
                break;

            case '*':
                *num = a*b;
                break;

            case '/':
                *num = b/a;
                break;
            }
            push_stack(&st,num);
            ++formula;
        }else if(*formula != ' '){
            break_stack(st);
            longjmp(for_error,-1);
        }
        ++formula;
    }
    if(top_stack(&st) == NULL){
        break_stack(st);
        longjmp(for_error,-1);
    }
    Ret = *(double*)top_stack(&st);
    free(top_stack(&st));
    pop_stack(&st);
    break_stack(st);
    return Ret;
}

 

 

main.c

#include <stdio.h>
#include <setjmp.h>
#include "infix2postfix.h"
#include "eval4rules.h"

int main()
{  
    int i;
    double n;
    char formula[300];
    char Result[10000] = "";
    jmp_buf env;
    i = setjmp(env);
    if(i == 0){
        scanf("%s",formula);
        convert(formula,Result);
        n = evaluation(Result,env);
        printf("n:%f\n",n);
        return 0;
    }else if(i == -1){
        puts("SyntaxError");
        return -1;
    }else if(i == -2){
        puts("Stack memory limits");
        return -1;
    }
}

 

テストなので字句解析とかすっ飛ばしてるけど今ちゃんと書いてるので。

あと、エラー処理適当かなと。

stack,queueの実装

出来上がったと思うので一応うp

 

stack

 

#define make_stack(x); stack x;x.last=NULL;
#define make_stack_p(x); stack *(x)=(stack*)malloc(sizeof(stack));(x)->last=NULL;
#define break_stack(x); while(top_stack(&x)!=0x00000000){pop_stack(&x);}
#define break_stack_p(x); while(top_stack(x)!=0x00000000){pop_stack(x);}free(x);

struct _Stack{
  void *content;
  struct _Stack *front;
};
 
typedef struct{
  struct _Stack *last;
}stack;
 
void *top_stack(stack *st){
  if(st->last == NULL){
    return (void*)0x00000000;
  }
  return st->last->content;
}


int push_stack(stack *st, void *variable){
  struct _Stack *tmp;
  tmp = (struct _Stack*)malloc(sizeof(struct _Stack));
  if(tmp == NULL)return -1;
  if(st->last == NULL){
    tmp->front = NULL;
  }else{
    tmp->front = st->last;
  }
  tmp->content = variable;
  st->last = tmp;
  return 0;
}

void *pop_stack(stack *st){
  if(st->last == NULL)return NULL;
  if(st->last->front == NULL){
    st->last = NULL;
  }else{
    struct _Stack *tmp = st->last;
    st->last = st->last->front;
    free(tmp);
  }
  return NULL;
}

 

 

queue

 

#define make_queue(x) queue x;x.first=NULL
#define make_queue_p(x) queue *(x)=(queue*)malloc(sizeof(queue));(x)->first=NULL
#define break_queue(x) while(top_queue(&x)!=0x00000000){pop_queue(&x);}
#define break_queue_p(x) while(top_queue(x)!=0x00000000){pop_queue(x);}free(x);

struct _Queue{
  void *content;
  struct _Queue *next;
};
 
typedef struct{
  struct _Queue *first;
  struct _Queue *last;
}queue;
 
void *top_queue(queue *que){
  if(que->first == NULL)return 0x00000000;
  return que->first->content;
}
 
int push_queue(queue *que, void *variable){
  struct _Queue *tmp;
  tmp = (struct _Queue*)malloc(sizeof(struct _Queue));
  if(tmp == NULL)return -1;
  tmp->content = variable;
  if(que->first == NULL)que->first = tmp;
  que->last = tmp;
  return 0;
}
 
void *pop_queue(queue *que){
  if(que->first == NULL)return NULL;
  if(que->first->next == NULL){
    que->first = NULL;
    que->last = NULL;
  }else{
    struct _Queue *tmp = que->first;
    que->first = que->first->next;
    free((void*)tmp);
  }
  return NULL;
}

 

 

 

scanf

後輩の質問を受けた。

中1は基本的にC言語Javaの勉強をしていて、AOJ解けって言ってた。

「AOJのVolume5の501がわかりません」

要は、文字列を変換するリストと、文字列が与えられるので変換後の文字列を出力しろと(nの上限決まってなかったりで疑問なんだが)。

んで、その中1はちゃんと自分の書いたソース載せてたのでちょっと書き加えた。

#include <stdio.h>

int main()
{
  int n,m,i,j;
  char a[1000],b[1000];
  while(1){
    scanf("%d",&n);
    if(n == 0)return 0;
    for(i = 0;i < n;i++){
      scanf(" %c %c", &a[i], &b[i]);
    }
    scanf("%d", &m);
    for(i = 0;i < m;i++){
      char c;
      scanf(" %c",&c);
      for(j = 0;j < n;j++){
        if(c == a[j]){
            c = b[j];
            break;
        }
      }
      printf("%c",c);
    }
    puts("");
  }
}

ハマったのがscanf。

はじめ、

scanf("%d", &n);

scanf("%c",&c[i]);

という風にしていたんだけれども、

アウトプットミスってるし

入力待ちがどうも想定してるインプットより少ないのでおかしいと思った。

出力よく見てると改行されてるので、scanf("%c\n",&c[i])にした。

すると、アウトプットは正しくなったが、逆にインプットを多く求められた。

 

結構ハマったあげく、調べてみるとこういうふうにあった。

http://www.pc.uec.ac.jp/sp/hshrkw/edu/program/b1/Ex2-1b.htm
初歩的なことなんだけど忘れてるとハマる。

結局、scanf(" %c",&c[i])にすることでうまく動いた。

気をつけよう(戒め)

stackの実装(続き)

とりあえず実装出来ました。

やっちゃいけないことしてる感があるのと、これでもまだ不完全なのが…(というか、なんで俺はC++使わない縛りをしているんだ?


#define make_stack(x) stack x;x.last=NULL
#define make_stack_p(x) stack *x=(stack*)malloc(sizeof(stack));x->last=NULL

struct _Stack{
  void *content;
  struct _Stack *front;
};
 
typedef struct{
  struct _Stack *last;
}stack;
 
void *top(stack *st){
  if(st->last == NULL){
    return (void*)0x0;
  }
  return st->last->content;
}
 
int push(stack *st, void *variable){
  struct _Stack *tmp;
  tmp = (struct _Stack*)malloc(sizeof(struct _Stack));
  if(tmp == NULL)return -1;
  if(st->last == NULL){
    tmp->front = NULL;
  }else{
    tmp->front = st->last;
  }
  tmp->content = variable;
  st->last = tmp;
  return 0;
}
 
void *pop(stack *st){
  if(st->last == NULL)return NULL;
  if(st->last->front == NULL){
    st->last = NULL;
  }else{
    struct _Stack *tmp = st->last;
    st->last = st->last->front;
    free(tmp);
  }
  return NULL;
}

 

ええ、はい。そうです。defineです。

make_stackで宣言してもらうことでメンバ変数の初期化もこなしました。

しかし、これだと(もしかしたらあるんかな)定義していないダブルポインタ以上は扱えないという事に…

よろしくないので、どうにかしたいですね。