C言語関係掲示板

過去ログ

No.1093 変数=値で値を記憶、変数を入力したら記憶した値を表示

[戻る] [ホームページ]
No.14372

記憶させる
投稿者---gammd(2004/06/01 22:09:03)


変数=値となったら、その値を記憶して、変数だけ入力したら
記憶した値を表示させたいのですが、行き詰まりました。
>x=18
>yz = 19
>x
18
>yz
19


のようにさせたいんです。
以下のソースを発展させたいのですが、どなたか教えてください。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX 256
#define MAX_VAR_LENGTH 256  /* 変数の最大文字数 */
#define N_VAR 256         /* 変数の最大数 */   

struct varEntry { /* 「変数=値」の構造体 */
    char name[MAX_VAR_LENGTH]; /* 変数の名前 */
    int value; /* とその値 */
} varTable[N_VAR];

int get_token(const char *p, char *token)
{
    int c = *p;
    if (c == '\n') {
        *token++ = c; *token = 0;
        return 'H';
    }
    if (c == '=') {
        *token++ = c; *token = 0;
        return 'Q';
    }
    if (strchr("+-*/", c)) { 
        *token++ = c;  *token = 0; 
        return 'O';
    } 
    if (c == ' ') {
        do { *token++ = c; 
        c = *++p; } while (c == ' ');
        *token = 0;
        return 'B';
    }
    if (isdigit(c)) {
        do { *token++ = c; 
        c = *++p; } while (isdigit(c));
        *token = 0;
        return 'N';
    }
    if (isalpha(c)) {
        do { *token++ = c; 
        c = *++p; } while (isalpha(c));
        *token = 0;
        return 'A';
    }
    *token++ = c;  *token = 0;
    return 'E';
}

int main(void)
{
    char buf[MAX], token[MAX],*p;
    int class,num[3];
    int op = 0,i = 0;

  START:
    while (printf(">"), fgets(buf, MAX, stdin) && *buf != '.') {
        i=0;
        for (p=buf ;*p; p += strlen(token)) {
            class = get_token(p, token);
            
            if(class == 'N'){
                printf("%s 数値\n", token);
            }
            else if(class == 'O'){
                printf("%s 演算子\n", token);
            }
            else if(class == 'A'){
                printf("%s 変数\n", token);
            }
            else if(class == 'Q'){
                printf("%s 代入演算子\n", token);
            }
            else if(class == 'E'){
                printf("ERROR\n");
                goto START;
            }
        }
    }
}




No.14374

Re:記憶させる
投稿者---かずま(2004/06/01 23:25:48)


> 以下のソースを発展させたいのですが、どなたか教えてください。

そのソースとは全然関係なくて申し訳ありませんが、何かの参考にはなるでしょう。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TABLE_SIZE  256
#define BUF_SIZE    256

int main(void)
{
    struct { char *name; int val; } table[TABLE_SIZE];
    int size = 0, val, i;
    char buf[BUF_SIZE], name[BUF_SIZE], c;

    while (printf("> "), fgets(buf, BUF_SIZE, stdin) && *buf != '.')
        if (sscanf(buf, " %[a-z] =%d %c\n", name, &val, &c) == 2) {
            for (i = 0; i < size && strcmp(table[i].name, name); i++) ;
            if (i == size) {
                if (i == TABLE_SIZE) puts("too many variables"), exit(1);
                table[size++].name = strdup(name);
            }
            table[i].val = val;
        }
        else if (sscanf(buf, " %[a-z] %c", name, &c) == 1) {
            for (i = 0; i < size && strcmp(table[i].name, name); i++) ;
            if (i == size) puts(" not defined");
            else printf("%d\n", table[i].val);
        }
        else puts("ERROR");
    return 0;
}



No.14375

Re:記憶させる
投稿者---かずま(2004/06/01 23:32:06)


>       if (sscanf(buf, " %[a-z] =%d %c\n", name, &val, &c) == 2) {

訂正
        if (sscanf(buf, " %[a-z] =%d %c", name, &val, &c) == 2) {



No.14393

Re:記憶させる
投稿者---gammd(2004/06/02 18:10:49)


このソースに、
>x= 10
>x
10
>y = x+5
15


としたいんですけど、無理ですかね?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX 256
#define N_VAR 256           

struct varEntry {
  char *name;
  int val;
} varTable[N_VAR];

int get_token(const char *p, char *token)
{
    int c = *p;
    if (c == '\n') {
        *token++ = c;
        *token = 0;
        return 'H';
    }
    if (c == '=') {
        *token++ = c;
        *token = 0;
        return 'Q';
    }
    if (strchr("+-*/", c)) { 
        *token++ = c; 
        *token = 0; 
        return 'O';
    } 
    if (c == ' ') {
        do { *token++ = c; 
        c = *++p; } while (c == ' ');
        *token = 0;
        return 'B';
    }
    if (isdigit(c)) {
        do { *token++ = c; 
        c = *++p; } while (isdigit(c));
        *token = 0;
        return 'N';
    }
    if (isalpha(c)) {
        do { *token++ = c; 
        c = *++p; } while (isalpha(c));
        *token = 0;
        return 'A';
    }
    *token++ = c; 
    *token = 0;
    return 'E';
}

int main(void)
{
    char line[MAX], token[MAX];
    char *p;
    int class;
    int num[3];
    int op = 0;
    int i = 0, j = 0;
    int val;
    char c;
    int size =0;

    while (printf(">"), fgets(line, MAX, stdin) && *line != '.') {
        if(sscanf(line, " %[a-z] =%d %c", token, &val, &c) == 2) {
            for (j = 0; j < size && strcmp(varTable[j].name, token); j++) ;
            if (j == size) {
                if (j == N_VAR) puts("too many variables"), exit(1);
                varTable[size++].name = strdup(token);
            }
            varTable[j].val = val;
        }
        else if (sscanf(line, " %[a-z] %c", token, &c) == 1) {
            for (j = 0 ; j < size && strcmp(varTable[j].name, token) ; j++) ;
            if (j == size) puts(" not defined");
            else printf("%d\n", varTable[j].val);
        }
        i=0;
        for (p=line ; *p ; p += strlen(token)) {
            class = get_token(p, token);
            if(class == 'E'){
                printf("ERROR\n");
                break;
            }
            if (class == 'N' && i < 2) num[i++] = atoi(token);
            if (class == 'O') op = *token;
        }
        if (i == 2)
            switch (op) {
              case '+': printf("%d\n", num[0] + num[1]); break;
              case '-': printf("%d\n", num[0] - num[1]); break;
              case '*': printf("%d\n", num[0] * num[1]); break;
              case '/': printf("%d\n", num[0] / num[1]); break;
            }
    }
}



No.14394

Re:記憶させる
投稿者---かずま(2004/06/02 20:14:20)


> >x= 10
> >x
> 10
> >y = x+5
> 15
>
> としたいんですけど、無理ですかね?
無理ですね。x=... のときは値を表示しないのに、y=... のときは値を
表示するというような気まぐれな仕様は理解できません。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

enum { VAR_SIZE = 200, BUF_SIZE = 256 };

double vals[VAR_SIZE];  int size, tok;
char *names[VAR_SIZE], name[BUF_SIZE], buf[BUF_SIZE], *bp, o[] = "+-*/";

int get(void) { do tok = *bp++ & 0xFF; while (isspace(tok)); return tok; }

double expr(const char *s)
{
    double val;  int i;

    if (*s)
        for (val = expr(s+2); tok == s[0] || tok == s[1]; )
            switch (tok) {
              case '+': val += expr(s+2); break;
              case '-': val -= expr(s+2); break;
              case '*': val *= expr(s+2); break;
              case '/': val /= expr(s+2); break;
            }
    else if (get()=='(') val = expr(o), tok==')' ? get() : (tok = 1);
    else if (tok == '-') val = -expr(s);
    else if (tok == '+') val = expr(s);
    else if (tok == '.' || isdigit(tok)) val = strtod(bp-1, &bp), get();
    else if (islower(tok)) {
        sscanf(bp-1, "%[a-z]%n", name, &i), bp += i-1, get();
        for (i = 0; i < size && strcmp(names[i], name); i++) ;
        val = (i == size) ? (tok = 1) : vals[i];
    }
    else val = tok = 1;
    return val;
}

int main(void)
{
    double val;  int i;  char c;

    while (printf("> "), fgets(buf, BUF_SIZE, stdin) && *buf != '.')
        if (sscanf(buf, " %[a-z] = %c", name, &c) == 2) {
            for (i = 0; i < size && strcmp(names[i], name); i++) ;
            if (i == size)
                if (i == VAR_SIZE) break;
                else names[size++] = strdup(name);
            bp = strchr(buf, '=') + 1,  val = expr(o);
            tok ? puts(" error") : (vals[i] = val);
        }
        else if (sscanf(buf, " %[a-z] %c", name, &c) == 1) {
            for (i = 0; i < size && strcmp(names[i], name); i++) ;
            i == size ? puts(" error") : printf("%.15g\n", vals[i]);
        }
        else puts(" error");
    return 0;
}



No.14398

Re:記憶させる
投稿者---gammd(2004/06/03 00:20:02)


じゃあ、こういうのはどうですか?やっぱり無理ですか?
>x=4+5
9
>y = x + 1
10
>x
9


yには値が記憶されなくて、ただ普通に計算させたいのですが。


No.14400

Re:記憶させる
投稿者---RAPT(2004/06/03 01:09:20)


そういう風に作ればできるんじゃん?


No.14407

Re:記憶させる
投稿者---gammd(2004/06/03 11:19:41)


>そういう風に作ればできるんじゃん?

具体的にはどのように?
いろいろとやってはいるんですが...
やっぱりこのソースじゃ無理なんですかね?
記憶したやつと計算させたいんですけど。もちろん
普通の計算もできるようにして。
>x=1
>y = x + 9
10
>x
1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX 256
#define N_VAR 256           

struct varEntry {
  char *name;
  int val;
} varTable[N_VAR];

int get_token(const char *p, char *token)
{
    int c = *p;
    if (c == '\n') {
        *token++ = c;
        *token = 0;
        return 'H';
    }
    if (c == '=') {
        *token++ = c;
        *token = 0;
        return 'Q';
    }
    if (strchr("+-*/", c)) { 
        *token++ = c; 
        *token = 0; 
        return 'O';
    } 
    if (c == ' ') {
        do { *token++ = c; 
        c = *++p; } while (c == ' ');
        *token = 0;
        return 'B';
    }
    if (isdigit(c)) {
        do { *token++ = c; 
        c = *++p; } while (isdigit(c));
        *token = 0;
        return 'N';
    }
    if (isalpha(c)) {
        do { *token++ = c; 
        c = *++p; } while (isalpha(c));
        *token = 0;
        return 'A';
    }
    *token++ = c; 
    *token = 0;
    return 'E';
}

int main(void)
{
    char line[MAX], token[MAX];
    char *p;
    int class;
    int num[3];
    int op = 0;
    int i = 0, j = 0;
    int val;
    char c;
    int size =0;

    while (printf(">"), fgets(line, MAX, stdin) && *line != '.') {
        if(sscanf(line, " %[a-z] =%d %c", token, &val, &c) == 2) {
            for (j = 0; j < size && strcmp(varTable[j].name, token); j++) ;
            if (j == size) {
                if (j == N_VAR) puts("too many variables"), exit(1);
                varTable[size++].name = strdup(token);
            }
            varTable[j].val = val;
        }
        else if (sscanf(line, " %[a-z] %c", token, &c) == 1) {
            for (j = 0 ; j < size && strcmp(varTable[j].name, token) ; j++) ;
            if (j == size) puts(" not defined");
            else printf("%d\n", varTable[j].val);
        }
        i=0;
        for (p=line ; *p ; p += strlen(token)) {
            class = get_token(p, token);
            if(class == 'E'){
                printf("ERROR\n");
                break;
            }
            if (class == 'N' && i < 2) num[i++] = atoi(token);
            if (class == 'O') op = *token;
        }
        if (i == 2)
            switch (op) {
              case '+': printf("%d\n", num[0] + num[1]); break;
              case '-': printf("%d\n", num[0] - num[1]); break;
              case '*': printf("%d\n", num[0] * num[1]); break;
              case '/': printf("%d\n", num[0] / num[1]); break;
            }
    }
}







No.14409

Re:記憶させる
投稿者---あかま(2004/06/03 11:59:49)


>やっぱりこのソースじゃ無理なんですかね?
>記憶したやつと計算させたいんですけど。もちろん
>普通の計算もできるようにして。

ソースを読んでみたのですが、ごちゃごちゃしすぎて読みきれなかったのですよ。コメントもないですし。
題意にあるように、「記憶させる」の部分が出来てないのですよね?
そういう時は、「計算させる」部分のコードを取っ払ってしまうといいです。
それだけでバグ取りは相当容易になります。

最初に全部作ってからバグ取りをすると余計な手間がかかりますし、スパゲッティコードになりがちです。



No.14414

Re:記憶させる
投稿者---あかま(2004/06/03 13:50:15)


色々問題はありますが、それっぽく動くコードを。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX 256
#define N_VAR 256

struct varEntry {
  char *name;
  int val;
} varTable[N_VAR+3];

struct varEntry *get_varTp(char *token,int num){
    int val;
    int i;
    if(val = atoi(token)){//tokenが数字だった時
        varTable[N_VAR+num].val = val;
        return &varTable[N_VAR+num];
    }
    
    for (i = 0; varTable[i].name != NULL && strcmp(varTable[i].name, token); i++) ;
    if(i >= N_VAR) puts("too many variables"), exit(1);
    if(varTable[i].name == NULL){
        varTable[i].name = strdup(token);
    }
    return &varTable[i];

}

int main(void)
{
    struct varEntry *tk[3];
    char line[MAX], token[3][MAX];
    char op;
    int i,j,num;

    while (printf(">"), fgets(line, MAX, stdin) && *line != '.') {
        num = sscanf(line, " %s =%s %c %s", token[0],token[1], &op,token[2]);
        if(num == 4) num--;
        for(i = 0;i < num;i++){
            tk[i] = get_varTp(token[i],i);
        }
        
        if(num == 2){
            tk[0]->val = tk[1]->val;
        }
        else if(num == 3){
            switch (op) {
              case '+':
                tk[0]->val = tk[1]->val + tk[2]->val;
                break;
              case '-':
                tk[0]->val = tk[1]->val - tk[2]->val;
                break;
              case '*':
                tk[0]->val = tk[1]->val * tk[2]->val;
                break;
              case '/':
                tk[0]->val = tk[1]->val / tk[2]->val;
                break;
            }
        }
        printf("%d\n",tk[0]->val);
    }
    
    return 0;
}




No.14435

Re:記憶させる
投稿者---gammd(2004/06/03 20:15:44)


言葉足らずですみません。
細かに書きます。
まず、変数=値のときはその値を変数に記憶させる。
数式だったらそのまま計算させる。
もし、数式の中に変数があって、その変数が前に記憶させたもの
だったら、その変数と計算させる。
>1 + 2
3
>a=4+3
7
>a + 3
10


な感じにさせたいのですが。


No.14436

Re:記憶させる
投稿者---かずま(2004/06/03 20:35:32)


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

enum { VAR_SIZE = 200, BUF_SIZE = 256 };

double vals[VAR_SIZE];  int size, tok;
char *names[VAR_SIZE], name[BUF_SIZE], buf[BUF_SIZE], *bp, o[] = "+-*/";

int get(void) { do tok = *bp++ & 0xFF; while (isspace(tok)); return tok; }

double expr(const char *s)
{
    double val;  int i;

    if (*s)
        for (val = expr(s+2); tok == s[0] || tok == s[1]; )
            switch (tok) {
              case '+': val += expr(s+2); break;
              case '-': val -= expr(s+2); break;
              case '*': val *= expr(s+2); break;
              case '/': val /= expr(s+2); break;
            }
    else if (get()=='(') val = expr(o), tok==')' ? get() : (tok = 1);
    else if (tok == '-') val = -expr(s);
    else if (tok == '+') val = expr(s);
    else if (tok == '.' || isdigit(tok)) val = strtod(bp-1, &bp), get();
    else if (islower(tok)) {
        sscanf(bp-1, "%[a-z]%n", name, &i), bp += i-1, get();
        for (i = 0; i < size && strcmp(names[i], name); i++) ;
        val = (i == size) ? (tok = 1) : vals[i];
    }
    else val = tok = 1;
    return val;
}

int main(void)
{
    double val;  int i;  char c;

    while (printf("> "), fgets(buf, BUF_SIZE, stdin) && *buf != '.') {
        i = size;
        if (sscanf(buf, " %[a-z] = %c", name, &c) == 2) {
            for (i = 0; i < size && strcmp(names[i], name); i++) ;
            if (i == size)
                if (i == VAR_SIZE) break;
                else names[size++] = strdup(name);
            bp = strchr(buf, '=') + 1;
        }
        else bp = buf;
        val = expr(o);
        tok ? puts(" error") : printf("%.15g\n", val);
        if (i < size) vals[i] = val;
    }
    return 0;
}

----------------------------------------------------------
> circle = 355
355
> diameter = 113
113
> pi = circle / diameter
3.14159292035398
> .



No.14438

Re:記憶させる
投稿者---gammd(2004/06/03 21:03:21)


かずまさん、ありがとうございます。
このソースを参考にやってみます。



No.14439

Re:記憶させる
投稿者---RAPT(2004/06/03 22:20:20)


昔書いたPerlの連想配列もどきをリスト構造で書いたもの。
# C++なら map 使えばいいだけだけど。
リストを使えば、使用できる変数の制限はメモリ依存。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/* bool型の代替 */
#ifndef BOOL
#define BOOL int
#define TRUE 1
#define FALSE 0
#endif

/* 格納する変数の型 */
#define VAR_TYPE  double

/*************************************************************
  ノードの構造体定義
  先頭ノードはデータを入れないで使用する
 *************************************************************/
typedef struct st_ASOVAR_TYPE{
  struct st_ASOVAR_TYPE *pNext; /* 次のノードへのポインタ */
  VAR_TYPE var; /* 変数 */
  char *pName;  /* 変数名 */
} ASOVAR_TYPE;


/*************************************************************
  先頭ノードのポインタ宣言
 *************************************************************/
static ASOVAR_TYPE *pStart;


/*************************************************************
  ノードを扱うための関数定義
 *************************************************************/
/* ノードの実体を作成する。失敗したらNULLを返す */
ASOVAR_TYPE *newNode(){
  return (ASOVAR_TYPE *)calloc(1, sizeof(ASOVAR_TYPE));
}

/* 先頭ノードの末尾に変数名と変数のアドレスを登録する */
BOOL addVarList(const char *pName, VAR_TYPE var){
  ASOVAR_TYPE *pT = pStart, *pTnew;
  if(0 == strlen(pName)){
    return FALSE;
  }
  pTnew = newNode();
  if(pTnew == NULL){
    return FALSE;
  }

  pTnew->pName = strdup(pName);
  if(pTnew->pName == NULL){
    free(pTnew);
    return FALSE;
  }

  pTnew->pNext = NULL;
  pTnew->var = var;

  /* ノードの最後に追加 */
  while(pT->pNext){
    pT = pT->pNext;
  }
  pT->pNext = pTnew;

  return TRUE;
}

/* 変数名が合致するノードを返す。見つからなければNULLを返す */
ASOVAR_TYPE *getNode(const char *pName){
  ASOVAR_TYPE *pT = pStart->pNext;
  while(pT){
    if (0 == strcmp(pT->pName, pName)){
      return pT;
    }
    pT = pT->pNext;
  }
  return NULL;
}

/* 初期処理:先頭ノードの実体作成 */
void init(){
  pStart = newNode();
};

/* 後処理:ノードで確保されたメモリの開放 */
void term(){
  ASOVAR_TYPE *pT = pStart;
  while(pT){
    pStart = pStart->pNext;
    free(pT->pName);
    free(pT);
    pT = pStart;
  }
};


/*************************************************************
  連想配列もどきの操作関数
 *************************************************************/
/* 指定変数名の変数に値を代入する */
BOOL setValue(const char *pName, const VAR_TYPE var){
  ASOVAR_TYPE *pT = getNode(pName);
  if(pT){
    pT->var = var;
    return TRUE;
  }
  return FALSE;
}

/* 指定変数名の変数から値を取り出す */
VAR_TYPE getValue(const char *pName){
  ASOVAR_TYPE *pT = getNode(pName);
  if(pT){
    return pT->var;
  }
  return 0;
}


/*************************************************************
  連想配列もどきの使用例
 *************************************************************/
int main()
{
  /* 初期処理 */
  init();

  /* 初期化 */
  addVarList("A", 0);
  addVarList("B", 3.14);

  /* 中身確認 */
  printf("初期状態の中身------\n");
  printf("A=%f\n", getValue("A"));
  printf("B=%f\n", getValue("B"));

  /* 代入処理 */
  setValue("A", 12);
  setValue("B", 12345);

  /* 中身確認 */
  printf("代入後の中身--------\n");
  printf("B=%f\n", getValue("B"));
  printf("A=%f\n", getValue("A"));

  /* 後処理 */
  term();

  return 0;
}

----------------------------------------

初期状態の中身------
A=0.000000
B=3.140000
代入後の中身--------
B=12345.000000
A=12.000000



No.14441

Re:記憶させる
投稿者---かずま(2004/06/04 11:41:46)


>       tok ? puts(" error") : printf("%.15g\n", val);

これを次のように変更します。

        if (tok) { puts(" error"); continue; }
        printf("%.15g\n", val);
        if (i < size) vals[i] = val;



No.14478

Re:記憶させる
投稿者---gammd(2004/06/05 13:22:44)


sscanfを使わない方向で、自分で考えたんですけど、
ソースを見てもらえば分かるんですが、下の3つの関数が未完成なんです。とりあえず、記憶だけさせたいんですが、アドバイス
お願いします。
#include <stdio.h>  
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h>  

#define TRUE 1
#define FALSE 0

#define MAX 256             /* 文字列の長さ */
#define MAX_VAR_LENGTH 256  /* 変数の最大文字数 */
#define N_VAR 256           /* 変数の最大数 */

struct varEntry{
   char name[MAX_VAR_LENGTH]; /* 変数名 */
   int value;                 /* 現在の値 */
} varTable[N_VAR];

int getToken(const char *, char *); /* トークン切り出し関数 */
int isOperator(char);               /* 演算子判定関数 */
int setVar(char *, char *);         /* 変数定義関数 */
int getVar(char *, char *);         /* 変数定義判定関数 */
void printVar(char *);              /* 出力関数 */

main()
{
  char line[MAX];     /* 入力データを格納する配列 */
  char token[MAX];    /* 出力データを格納する配列 */
  char *p;            /* ポインタ */
  int classToken;     /* 変数の状態*/
  int num[3];         /* 数値を格納する配列 */
  int op = 0;         /* 演算子の判定 */
  int i;              /* 配列操作変数 */
  int size;           /**/
 
  printf(">"); /* プロンプト表示 */
  while ( fgets(line, MAX, stdin) ) { 
    /* キーボードからデータを受け取る */
 
    i=0; /* 初期化 */
    for (p = line ; *p ; p += strlen(token)) { 
      
      classToken = getToken(p, token); /* 状態をclassTokenへ渡す */

      if ( classToken == 'T') exit(0);             /* ピリオドなら終了 */
      if ( classToken == 'E') printf("ERROR\n");   /* エラー表示 */
      if ( classToken == 'N' && i < 3 ) num[i++] = atoi(token); 
                                                  /* 文字列を数値へ */
      if ( classToken == 'O') op = *token; 
                                                  /* opへ演算子をコピー */
    } /* for */
    
    if (i == 2)
      switch (op) {
      case '+': printf("%d\n", num[0] + num[1]); break;
      case '-': printf("%d\n", num[0] - num[1]); break;
      case '*': printf("%d\n", num[0] * num[1]); break;
      case '/': printf("%d\n", num[0] / num[1]); break; 
      } /* switch */
    
    printf(">");

  } /* while */
  
}


/* ******************** */
/* トークン切り出し関数 */
/* ******************** */

int getToken(const char *p, char *token)
{
  int c = *p; /* トークンをcへ */

   if( c == '.'){ /* cがピリオドなら */
    *token++ = c;
    *token = 0;
    return 'T';
  } /* if */
  
  if ( c == '\n' ) { /* cが改行なら */
    *token++ = c; 
    *token = 0; 
    return 'H';      /* 改行の状態 */ 
  } /* if */
  
  if ( islower(c) ){ /* cが変数なら */
    do { 
      *token++ = c; 
      c = *++p; 
    } while ( islower(c) );
    *token = 0;
    return 'V';      /* 英小文字の状態 */
  } /* if */
  
  if ( isOperator(c) ) { /* cが演算子なら */
    *token++ = c; 
    *token = 0; 
    return 'O';      /* 演算子の状態 */
  } /* if */ 
  
  if ( c == '=' ) {  /* cが代入演算子なら */
    *token++ = c;
    *token = 0;
    return 'S';      /* "="の記号の状態 */
  } /* if */
  
  if ( c == ' ' ) {  /* cがスペースなら */
    do { 
      *token++ = c; 
      c = *++p; 
    } while ( c == ' ' );
    *token = 0;
    return 'B';      /* スペースの状態 */
    }/* if */
  
  if ( isdigit(c) ) { /* cが数値なら */
    do { 
      *token++ = c; 
      c = *++p; 
    } while ( isdigit(c) );
    *token = 0;
    return 'N'; /* 数字の状態 */
  } /* if */
  
  /* それ以外のものは */
    *token++ = c; 
    *token = 0;
    return 'E'; /* それ以外の状態 */
    
    return 0; /* 正常終了 */
    
}

/* ************** */
/* 演算子判定関数 */ 
/* ************** */

int isOperator(char token)
{
  return token == '+' || token == '-' || token == '*' || token == '/';
  /* それぞれの演算子を返す*/
}

/* ************ */
/* 変数定義関数 */ 
/* ************ */

int setVar(char *var, char *value)
{
  varTable[N_VAR].name = value;
  変数が未定義なら;
  新しく定義する;
  return TRUE;
  既定義なら;
  その変数に値をセットする;
  return FALSE;
}

/* **************** */
/* 変数定義判定関数 */ 
/* **************** */

int getVar(char *var, char *value)
{
  value = varTable[N_VAR].name;
  return TRUE;
  変数が未定義なら;
  return FALSE;
}
   
/* ******** */
/* 出力関数 */ 
/* ******** */

void printVar(char *var) /* 指定された変数の値を返す */
{
  変数があれば;
  varの値を表示する;
  変数が無ければ;
  ERRORを表示;
}




No.14480

Re:記憶させる
投稿者---あかま(2004/06/05 14:05:48)


int setVar(char *var, char *value)
{
  int i;
  //↓せっかくgetVar()があるので使いたいのだが、戻り値がTRUEとFALSEしかないので使えない。
  //getVarの戻り値を工夫するといいんでない?見つかったらiを返す。見つからなければ-1とか。
  for (i = 0; varTable[i].name != NULL && strcmp(varTable[i].name, token); i++) ;
  if(varTable[i].name == NULL){//変数が未定義なら;
        varTable[i].name = strdup(token);//新しく定義する;
        varTable[i].value = atoi(value);
        return TRUE;
    }
  
  //既定義なら;
  varTable[i].value = atoi(value);//その変数に値をセットする;
  return FALSE;
}

/* **************** */
/* 変数定義判定関数 */ 
/* **************** */

int getVar(char *var, char *value)
{
  for (i = 0; varTable[i].name != NULL && strcmp(varTable[i].name, token); i++) ;
  if(varTable[i].name == NULL){//変数が未定義なら;
    return FALSE;//変数が未定義なら;
  }
  //既定義なら;
  return TRUE;
  
}
   
/* ******** */
/* 出力関数 */ 
/* ******** */

void printVar(char *var) /* 指定された変数の値を返す */
{
  for (i = 0; varTable[i].name != NULL && strcmp(varTable[i].name, token); i++) ;
  if(varTable[i].name == NULL){//変数が無ければ;
       puts("ERROR");//ERRORを表示;
  }
  
  //変数があれば;
  //varの値を表示する;
  printf("%d",vaTable[i].value);
  
}



No.14484

Re:記憶させる
投稿者---gammd(2004/06/05 19:44:09)


もう一つ、質問があるんです。
もし、関数が完成したら載せたソースのどこで使えばいいん
でしょうか?
>x = 10
>y=1
>x
10
>y
1
>z 11
ERROR
>

みたくしたいのですが


No.14485

Re:記憶させる
投稿者---あかま(2004/06/05 20:12:19)


>もし、関数が完成したら載せたソースのどこで使えばいいんでしょうか?
さぁ?
もしかしてなんとなく作ってただけ?

そもそも↓の

>x = 10
>y=1
>x
10
>y

構文解釈ができているかも怪しいような。
getToken()はきちんと動いてますか?
きちんとトークンが切り出せているなら適宜返り値にあわせて使えばいいのでは?

あなたの作ったプログラムを私が解説する不思議な関係。恋しそう。


No.14497

Re:記憶させる
投稿者---gammd(2004/06/06 14:38:42)


>getToken()はきちんと動いてますか?
getToken()はちゃんと動作します。
なんか、違うような気がするんですが書いてみました。
#include <stdio.h>  
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h>  

#define TRUE 1
#define FALSE 0
#define NG -1
#define MAX 256             /* 文字列の長さ */
#define MAX_VAR_LENGTH 256  /* 変数の最大文字数 */
#define N_VAR 256           /* 変数の最大数 */

struct varEntry{
   char name[MAX_VAR_LENGTH]; /* 変数名 */
   int value;                 /* 現在の値 */
} varTable[N_VAR];

int getToken(const char *, char *); /* トークン切り出し関数 */
int isOperator(char);               /* 演算子判定関数 */
int setVar(char *, char *);         /* 変数定義関数 */
int getVar(char *, char *);         /* 変数定義判定関数 */
void printVar(char *);              /* 出力関数 */

main()
{
  char line[MAX];     /* 入力データを格納する配列 */
  char token[MAX];    /* 出力データを格納する配列 */
  char *p;            /* ポインタ */
  int classToken;     /* 変数の状態*/
  int num[3];         /* 数値を格納する配列 */
  int op = 0;         /* 演算子の判定 */
  int i;              /* 配列操作変数 */
  int size;           /**/
  int VAR1, VAR2;
 
  printf(">"); /* プロンプト表示 */
  while ( fgets(line, MAX, stdin) ) { 
    /* キーボードからデータを受け取る */
 
    i=0; /* 初期化 */
    for (p = line ; *p ; p += strlen(token)) { 
      
      classToken = getToken(p, token); /* 状態をclassTokenへ渡す */

      if ( classToken == 'T' ) exit(0);                           /* ピリオドなら終了 */
      if ( classToken == 'E' ) printf("ERROR\n");                 /* エラー表示 */
      if ( classToken == 'N' && i < 3 ) num[i++] = atoi(token);   /* 文字列を数値へ */
      if ( classToken == 'O' ) op = *token;                       /* opへ演算子をコピー */
      if ( classToken == 'V' ){ 
          VAR1 = setVar(token, token);
          VAR2 = getVar(token, token);
          if ( VAR1 == 1 || VAR2 == i){
              printVar( varTable[i].name );
          } else 
              printVar( varTable[i].name );
      }
    } /* for */
    
    if (i == 2)
      switch (op) {
      case '+': printf("%d\n", num[0] + num[1]); break;
      case '-': printf("%d\n", num[0] - num[1]); break;
      case '*': printf("%d\n", num[0] * num[1]); break;
      case '/': printf("%d\n", num[0] / num[1]); break; 
      } /* switch */
    
    printf(">");

  } /* while */
  
}


/* ******************** */
/* トークン切り出し関数 */
/* ******************** */

int getToken(const char *p, char *token)
{
  int c = *p; /* トークンをcへ */

   if( c == '.'){ /* cがピリオドなら */
    *token++ = c;
    *token = 0;
    return 'T';
  } /* if */
  
  if ( c == '\n' ) { /* cが改行なら */
    *token++ = c; 
    *token = 0; 
    return 'H';      /* 改行の状態 */ 
  } /* if */
  
  if ( islower(c) ){ /* cが変数なら */
    do { 
      *token++ = c; 
      c = *++p; 
    } while ( islower(c) );
    *token = 0;
    return 'V';      /* 英小文字の状態 */
  } /* if */
  
  if ( isOperator(c) ) { /* cが演算子なら */
    *token++ = c; 
    *token = 0; 
    return 'O';      /* 演算子の状態 */
  } /* if */ 
  
  if ( c == '=' ) {  /* cが代入演算子なら */
    *token++ = c;
    *token = 0;
    return 'S';      /* "="の記号の状態 */
  } /* if */
  
  if ( c == ' ' ) {  /* cがスペースなら */
    do { 
      *token++ = c; 
      c = *++p; 
    } while ( c == ' ' );
    *token = 0;
    return 'B';      /* スペースの状態 */
    }/* if */
  
  if ( isdigit(c) ) { /* cが数値なら */
    do { 
      *token++ = c; 
      c = *++p; 
    } while ( isdigit(c) );
    *token = 0;
    return 'N'; /* 数字の状態 */
  } /* if */
  
  /* それ以外のものは */
    *token++ = c; 
    *token = 0;
    return 'E'; /* それ以外の状態 */
    
    return 0; /* 正常終了 */
    
}

/* ************** */
/* 演算子判定関数 */ 
/* ************** */

int isOperator(char token)
{
  return token == '+' || token == '-' || token == '*' || token == '/';
  /* それぞれの演算子を返す*/
}

/* ************ */
/* 変数定義関数 */ 
/* ************ */

int setVar(char *var, char *value)
{
    int i;
    char *token;

    for ( i = 0 ; varTable[i].name != NULL && strcmp(varTable[i].name, token) ; i++) ;
    if(varTable[i].name == NULL){          /* 変数が未定義なら */
        varTable[i].name = strdup(token);    /*新しく定義する */
        varTable[i].value = atoi(value);
        return TRUE;
    }
    varTable[i].value = atoi(value);       /* 既定義ならその変数に値をセットする */
    return FALSE;
}
 
/* **************** */
/* 変数定義判定関数 */ 
/* **************** */

int getVar(char *var, char *value)
{
    int i;
    char *token;

    for (i = 0 ; varTable[i].name != NULL && strcmp(varTable[i].name, token) ; i++) ;
    if(varTable[i].name == NULL){      /* 変数が未定義なら */
        return NG;                  
    }
    return i;                       /* 既定義なら */
}
   
/* ******** */
/* 出力関数 */ 
/* ******** */

void printVar(char *var)
{
    int i;
    char *token;

    for (i = 0 ; varTable[i].name != NULL && strcmp(varTable[i].name, token) ; i++) ;
    if(varTable[i].name == NULL){      /* 変数が無ければ */
        puts("ERROR");                 /* ERRORを表示 */
    }

    printf("%d\n",varTable[i].value);     /* 変数があればvarの値を表示する */

}




No.14502

Re:記憶させる
投稿者---あかま(2004/06/06 20:33:58)


/*
昨日作った関数コンパイルさえ通らなかったのでナンボか修正。

本題。
a = 12
という入力があったときに、変数aに12を代入するには
a
=
12
の3つのトークンを切り出してからじゃないと無理ですよね?

VAR1 = setVar(token, token);
なのでこれはありえない。

順序としては
1.式の入力
2.トークンを"全て"切り出し
3.トークンのパターンにしたがって処理
('='があったら直前のトークンに直後のトークンの値を代入など)
4.1.から繰り返し

とりあえず2.までやっときました。あとがんばってください。
切り出したトークンは
struct varEntry token[5];
に格納されていて
token[i].nameにトークンの文字列
token[i].valueにgetTokenの返り値

"a=12"の入力なら
token[0].name="a"
token[0].value='V'

token[1].name="="
token[1].value='S'

token[2].name="12"
token[2].value='N'
です。

ちなみに"a = 12"と入力するとERRORを返すのでどっかまちがってる。

スレッドが長くなってきたので続けるなら2スレ目を立てたほうがよさそうです。
*/

#include <stdio.h>  
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h>  

#define TRUE 1
#define FALSE 0
#define NG -1
#define MAX 256             /* 文字列の長さ */
#define MAX_VAR_LENGTH 256  /* 変数の最大文字数 */
#define N_VAR 256           /* 変数の最大数 */

struct varEntry{
   char name[MAX_VAR_LENGTH]; /* 変数名 */
   int value;                 /* 現在の値 */
} varTable[N_VAR];

int getToken(const char *, char *); /* トークン切り出し関数 */
int isOperator(char);               /* 演算子判定関数 */
int setVar(char *, char *);         /* 変数定義関数 */
int getVar(char *);         /* 変数定義判定関数 */
void printVar(char *);              /* 出力関数 */

main()
{
  char line[MAX];     /* 入力データを格納する配列 */
  struct varEntry token[5];
  char *p;            /* ポインタ */
  int ct;     /* 変数の状態*/
  int num[3];         /* 数値を格納する配列 */
  int i,j;              /* 配列操作変数 */
 
  printf(">"); /* プロンプト表示 */
  while ( fgets(line, MAX, stdin) ) { 
    
    i=0; /* 初期化 */
    for (p = line ; *p ; p += strlen(token[i-1].name)) { //"a = 12"でエラーはここかgetToken()のどちらかが原因だろう。たぶんここ。
        ct = getToken(p, token[i].name); /* 状態をclassTokenへ渡す */
        
        if ( ct == 'T' ) exit(0);
        if ( ct == 'E' ){printf("ERROR\n");exit(0);}
        if(ct == 'N' || ct == 'O' || ct == 'V' || ct == 'S'){
            token[i].value = ct;
            i++;
        }
    }
    //切り分けられたトークンの確認.いらなければ削除
    for(j =0;j < i; j++){
        printf("%s %c\n",token[j].name,token[j].value);
    }
    
    //ここからトークンのパターンにしたがってモニョモニョな処理
    
    //モニョモニョ終了
    
    printf(">");

  } /* while */
  
  return 0;
}


/* ******************** */
/* トークン切り出し関数 */
/* ******************** */

int getToken(const char *p, char *token)
{
  int c = *p; /* トークンをcへ */

   if( c == '.'){ /* cがピリオドなら */
    *token++ = c;
    *token = 0;
    return 'T';
  } /* if */
  
  if ( c == '\n' ) { /* cが改行なら */
    *token++ = c; 
    *token = 0; 
    return 'H';      /* 改行の状態 */ 
  } /* if */
  
  if ( islower(c) ){ /* cが変数なら */
    do { 
      *token++ = c; 
      c = *++p; 
    } while ( islower(c) );
    *token = 0;
    return 'V';      /* 英小文字の状態 */
  } /* if */
  
  if ( isOperator(c) ) { /* cが演算子なら */
    *token++ = c; 
    *token = 0; 
    return 'O';      /* 演算子の状態 */
  } /* if */ 
  
  if ( c == '=' ) {  /* cが代入演算子なら */
    *token++ = c;
    *token = 0;
    return 'S';      /* "="の記号の状態 */
  } /* if */
  
  if ( c == ' ' ) {  /* cがスペースなら */
    do { 
      *token++ = c; 
      c = *++p; 
    } while ( c == ' ' );
    *token = 0;
    return 'B';      /* スペースの状態 */
    }/* if */
  
  if ( isdigit(c) ) { /* cが数値なら */
    do { 
      *token++ = c; 
      c = *++p; 
    } while ( isdigit(c) );
    *token = 0;
    return 'N'; /* 数字の状態 */
  } /* if */
  
  /* それ以外のものは */
    *token++ = c; 
    *token = 0;
    return 'E'; /* それ以外の状態 */
    
    return 0; /* 正常終了 */
    
}

int isOperator(char token)
{
  return token == '+' || token == '-' || token == '*' || token == '/';
  /* それぞれの演算子を返す*/
}

int setVar(char *var, char *value)
{
    int i;

    for ( i = 0 ; varTable[i].name != NULL && strcmp(varTable[i].name,var) ; i++) ;
    if(varTable[i].name == NULL){          /* 変数が未定義なら */
        strcpy(varTable[i].name,var);    /*新しく定義する */
        varTable[i].value = atoi(value);
        return TRUE;
    }
    varTable[i].value = atoi(value);       /* 既定義ならその変数に値をセットする */
    return FALSE;
}

int getVar(char *var)
{
    int i;

    for (i = 0 ; varTable[i].name != NULL && strcmp(varTable[i].name,var) ; i++) ;
    if(varTable[i].name == NULL){      /* 変数が未定義なら */
        return NG;                  
    }
    return i;                       /* 既定義なら */
}

void printVar(char *var)
{
    int i;

    for (i = 0 ; varTable[i].name != NULL && strcmp(varTable[i].name,var) ; i++) ;
    if(varTable[i].name == NULL){      /* 変数が無ければ */
        puts("ERROR");                 /* ERRORを表示 */
    }
    printf("%d\n",varTable[i].value);     /* 変数があればvarの値を表示する */
}




No.14410

Re:記憶させる
投稿者---ぽこ(2004/06/03 13:00:41)


>具体的にはどのように?

これはgammdさんが決めることです。
例だけを示してもRAPTさんが答えられているように、
"そういう風に(例を満たすように)作れば?"というアドバイス以上の
ことは出来ません。

まず、どういうときに「記憶」し、どういうときに「計算」するのか
例を示すのではなくて、日本語で意味のブレがないように「入力をどう解釈するのか」を書くべきです。
ソースコードの良し悪しは、その次の段階の話です。



No.14376

Re:記憶させる
投稿者---RAPT(2004/06/01 23:36:45)


とりあえず、goto 文が目立ってますね。。
> goto START;
これは、break; とし、START: は削除しましょう。

それから、token が初期化されていないのに使用されています。

値の参照アルゴリズムとしては、入力文字列に '=' が含まれていなければ
値の参照とみなし、'=' が含まれていれば 値のセットをみなせばいいのでは?

それから、そもそも「変数」の名前付けのルールが記載されていませんが、
どういった仕様とするか決める必要があるのでは?
# 例えば、英数字のみで先頭に数字も許可、大文字小文字は同一視しない。
# 英数字以外の文字が指定されたらエラー、など。



No.14381

Re:記憶させる
投稿者---gammd(2004/06/02 11:10:31)


かずまさん、RAPTさん。ありがとうございました。
お二方のご指摘、例を参考にしながらがんばります。

No.14504

記憶させる2
投稿者---gammd(2004/06/06 22:05:01)


>"a = 12"と入力するとERRORを返すのでどっかまちがってる。
このエラーは数字が2文字以上になると出ます。
あと、あかまさんのいう
>2.トークンを"全て"切り出し
>3.トークンのパターンにしたがって処理
なら、以下のソースでできます。
>('='があったら直前のトークンに直後のトークンの値を代入など)
ここを、作った3つの関数でやるんですよね?
#include <stdio.h>  
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h>  

#define TRUE 1
#define FALSE 0
#define NG -1
#define MAX 256             /* 文字列の長さ */
#define MAX_VAR_LENGTH 256  /* 変数の最大文字数 */
#define N_VAR 256           /* 変数の最大数 */

struct varEntry{
   char name[MAX_VAR_LENGTH]; /* 変数名 */
   int value;                 /* 現在の値 */
} vT[N_VAR];

int getToken(const char *, char *); /* トークン切り出し関数 */
int isOperator(char);               /* 演算子判定関数 */
int setVar(char *, char *);         /* 変数定義関数 */
int getVar(char *, char *);         /* 変数定義判定関数 */
void printVar(char *);              /* 出力関数 */

main()
{
  char line[MAX], token[MAX];   
  char *p;       
  int cT,  int op = 0, i;          
  
  printf(">"); /* プロンプト表示 */
  while ( fgets(line, MAX, stdin) ) { 
      /* キーボードからデータを受け取る */
      
      i=0; /* 初期化 */
      for (p = line ; *p ; p += strlen(token)) { 
          cT = getToken(p, token); /* 状態をcTへ渡す */
          if(cT == 'N' || cT == 'O' || cT == 'S' || cT == 'V'){ 
              printf("%c : %s\n", cT, token);
          }
          if ( cT == 'T' ) exit(0);           /* ピリオドなら終了 */
          if ( cT == 'E' ) printf("ERROR\n"); /* エラー表示 */
      } /* for */
      
      printf(">");
  } /* while */
}

/* トークン切り出し関数 */
int getToken(const char *p, char *token)
{
    int c = *p; /* トークンをcへ */
    
    if( c == '.'){               /* cがピリオドなら */
        *token++ = c;  *token = 0;
        return 'T';
    } /* if */
    
    if ( c == '\n' ) {           /* cが改行なら */
        *token++ = c;  *token = 0; 
        return 'H';              /* 改行の状態 */ 
    } /* if */
    
    if ( islower(c) ){           /* cが変数なら */
        do { 
            *token++ = c;  c = *++p; 
        } while ( islower(c) );
        *token = 0;
        return 'V';              /* 英小文字の状態 */
    } /* if */
    
    if ( isOperator(c) ) {       /* cが演算子なら */
        *token++ = c; *token = 0; 
        return 'O';              /* 演算子の状態 */
    } /* if */ 
    
    if ( c == '=' ) {            /* cが代入演算子なら */
        *token++ = c; *token = 0;
        return 'S';              /* "="の記号の状態 */
    } /* if */
    
    if ( c == ' ' ) {            /* cがスペースなら */
        do { 
      *token++ = c; c = *++p; 
        } while ( c == ' ' );
        *token = 0;
        return 'B';              /* スペースの状態 */
    }/* if */
    
    if ( isdigit(c) ) {          /* cが数値なら */
        do { 
            *token++ = c; c = *++p; 
        } while ( isdigit(c) );
        *token = 0;
        return 'N';              /* 数字の状態 */
    } /* if */
    
    /* それ以外のものは */
    *token++ = c; *token = 0;
    return 'E';                  /* それ以外の状態 */
}

/* 演算子判定関数 */ 
int isOperator(char token)
{
    return token == '+' || token == '-' || token == '*' || token == '/';
    /* それぞれの演算子を返す*/
}

/* 変数定義関数 */ 
int setVar(char *var, char *value)
{
    int i;
    
    for ( i = 0 ; vT[i].name != NULL && strcmp(vT[i].name, var) ; i++) ;
    if(vT[i].name == NULL){          /* 変数が未定義なら */
        strcpy(vT[i].name, var);     /*新しく定義する */
        vT[i].value = atoi(value);
        return TRUE;
    }
    vT[i].value = atoi(value);       /* 既定義ならその変数に値をセットする */
    return FALSE;
}
 
/* 変数定義判定関数 */ 
int getVar(char *var, char *value)
{
    int i;

    for (i = 0 ; vT[i].name != NULL && strcmp(vT[i].name, var) ; i++) ;
    if(vT[i].name == NULL){      /* 変数が未定義なら */
        return NG;                  
    }
    return i;                       /* 既定義なら */
}
   
/* 出力関数 */ 
void printVar(char *var)
{
    int i;

    for (i = 0 ; vT[i].name != NULL && strcmp(vT[i].name, var) ; i++) ;
    if(vT[i].name == NULL){      /* 変数が無ければ */
        puts("ERROR");                 /* ERRORを表示 */
    }
    printf("%d\n",vT[i].value);     /* 変数があればvarの値を表示する */
}


No.14505

Re:記憶させる2
投稿者---あかま(2004/06/06 22:35:31)


>>"a = 12"と入力するとERRORを返すのでどっかまちがってる。
>このエラーは数字が2文字以上になると出ます。
ではがんばって直してください。
"a=12"だと2文字でもきっちり切り出せてるんですけどね。

>あと、あかまさんのいう
>>2.トークンを"全て"切り出し
>>3.トークンのパターンにしたがって処理
>なら、以下のソースでできます。
いや、すまん。書き方が悪かったようだ。切り出しても情報捨てては意味がない。

2.トークンを"全て"切り出し"保存"

だからその部分を変えないで。あなたがやるべきなのは変更ではなく追加。

なんでかってぇと入力には、
a = 3
12 + a
b = 13 + 5
c = a + b

とかいろいろパターンがあって、そのパターンごとにやるべき順番や処理が違いますよね?(基本は右辺の計算、左辺へ代入ですが)
そのパターンを判断するのにトークン切り出すごとに情報すてて出来ますか?
13+5を計算したら、直前にaや=があったことを忘れていては出来ませんよね?

>>('='があったら直前のトークンに直後のトークンの値を代入など)
>ここを、作った3つの関数でやるんですよね?
そうですね。

あとこれ。
int getVar(char *var, char *value)
value使ってないので
int getVar(char *var)
に直しておいてください。これも前回の投稿で直しておいたんですが。

No.14506

Re:記憶させる2
投稿者---gammd(2004/06/06 23:41:25)


ホント、すみません。
もう、何週間かやってて頭が・・・
追加とありますが、どのようにしたらいいんですか?
お願いします、教えてください。

No.14508

Re:記憶させる2
投稿者---かずま(2004/06/07 01:17:14)


#include <stdio.h>  
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h>  

#define TRUE   1
#define FALSE  0
#define MAX    256             /* 文字列の長さ */
#define MAX_VAR_LENGTH  256    /* 変数の最大文字数 */
#define N_VAR  256             /* 変数の最大数 */

struct varEntry{
    char name[MAX_VAR_LENGTH]; /* 変数名 */
    int value;                 /* 現在の値 */
} vT[N_VAR];

int  n_var = 0;                /* 定義済み変数の個数 */
char *tp;                      /* トークン切り出し位置 */

int  getToken(char *);         /* トークン切り出し関数 */
int  isOperator(char);         /* 演算子判定関数 */
void setVar(char *, int);      /* 変数定義関数 */
int  getVar(char *, int *);    /* 変数定義判定関数 */

int main(void)
{
    char line[MAX], token[MAX], var[MAX];
    int cT, op, num[2];

    while (printf(">"), fgets(line, MAX, stdin)) {
        tp = line;
        cT = getToken(var);
        if (cT == 'V') {
            cT = getToken(token);
            if (cT != 'S') var[0] = 0;
        }
        else var[0] = 0;

        if (var[0] == 0) tp = line;
        cT = getToken(token);
        if (cT == 'T') break;

        if (cT == 'V') {
            if (!getVar(token, &num[0])) { puts(" error"); continue; }
        }
        else if (cT == 'N') num[0] = atoi(token);
        else { puts(" error"); continue; }

        cT = getToken(token);
        if (cT == 'O') {
            op = *token;
            cT = getToken(token);
            if (cT == 'V') {
                if (!getVar(token, &num[1])) { puts(" error"); continue; }
            }
            else if (cT == 'N') num[1] = atoi(token);
            else { puts(" error"); continue; }
            switch (op) {
              case '+': num[0] += num[1]; break;
              case '-': num[0] -= num[1]; break;
              case '*': num[0] *= num[1]; break;
              case '/': num[0] /= num[1]; break;
            }
            cT = getToken(token);
        }
        if (cT != 'H') { puts(" error"); continue; }

        if (var[0]) setVar(var, num[0]);
        printf("%d\n", num[0]);
    }
    return 0;
}

int getToken(char *token)
{
    int c;

    do {
        c = *tp++ & 0xFF;
        if (c == '\n') { *token++ = c; *token = 0; return 'H'; }
    } while (isspace(c));
    if (islower(c)) {
        do { *token++ = c;  c = *tp++; } while (islower(c));
        *token = 0; tp--; return 'V';
    }
    if (isdigit(c)) {
        do { *token++ = c; c = *tp++; } while (isdigit(c));
        *token = 0; tp--; return 'N';
    }
    *token++ = c; *token = 0;
    if (isOperator(c)) return 'O';
    if (c == '=') return 'S';
    if (c == '.') return 'T';
    return 'E';
}

int isOperator(char token)
{
    return token == '+' || token == '-' || token == '*' || token == '/';
}

void setVar(char *var, int value)
{
    int i;

    for (i = 0 ; i < n_var && strcmp(vT[i].name, var) ; i++) ;
    if (i == n_var) strcpy(vT[n_var++].name, var);
    vT[i].value = value;
}

int getVar(char *var, int *value)
{
    int i;

    for (i = 0 ; i < n_var && strcmp(vT[i].name, var) ; i++) ;
    if (i == n_var) return FALSE;
    *value = vT[i].value;
    return TRUE;
}


No.14509

Re:記憶させる2
投稿者---かずま(2004/06/07 01:28:26)


理解度を試す質問です。

1. if (cT == 'O') を while (cT == 'O') に変えるとどうなるでしょうか?
2. printf("%d\n", num[0]); の前に else を置くとどうなるでしょうか?


No.14511

Re:記憶させる2
投稿者---gammd(2004/06/07 10:19:54)


>1. if (cT == 'O') を while (cT == 'O') に変えるとどうなるでしょうか?
結果は普通に返ってくるが、式を評価した後、またwhile(cT == 'O')
に戻ってしまう。

>2. printf("%d\n", num[0]); の前に else を置くとどうなるでしょうか?
「値=式」の時に記憶したままになり結果を返さない。

であってますか?


No.14533

Re:記憶させる2
投稿者---かずま(2004/06/09 20:25:55)


>> 1. if (cT == 'O') を while (cT == 'O') に変えるとどうなるでしょうか?
>
> 結果は普通に返ってくるが、式を評価した後、またwhile(cT == 'O')
> に戻ってしまう。

結果とは、何の結果ですか?  while (cT == '0') に戻ってどうなるのですか?

私の期待した回答は、「1+2+3+4 のように演算子が 2回以上使えるようになる」
でした。ただし、* や / を先にするということはできません。また、
while ループ中のエラー処理の continue; を変更しないといけませんね。


>> 2. printf("%d\n", num[0]); の前に else を置くとどうなるでしょうか?
>
> 「値=式」の時に記憶したままになり結果を返さない。

「値=式」?   12 = 4 * 3 ?

きっと、「変数 = 式」のつもりでしょう。
入力として許されるものを形式化して書けますか?
それができないと、プログラムがきちんと書けないと、私は思います。

仕様を次のように記述すればあいまいさがないと思いませんか?

  入力行 :  式 改行  |  変数 = 式 改行
  式     :  項  |  項 演算子 項
  演算子 :  +  |  -  |  *  |  /
  項     :  変数  |  定数
  変数   :  英小文字列
  定数   :  数字列

=, +, -, *, /, 英小文字列, 数字列, 改行がトークン。


ところで、
  トークンは普通空白を含まないもの。空白をトークンにすると、
  getToken の呼び出し元でそれを捨てるための余計な処理が必要になり面倒。

  トークン切り出し位置は、getToken が管理したほうが良い。
  getToken の呼び出し元でそれをやろうとすると余計な処理が必要になり面倒。

ということで、新しい getToken はそのようになっています。

なお、if (cT == 'O') を while (cT == 'O') に変えたものは、

  式     :  項  |  項 演算子 項  | 項 演算子 項 演算子 項
            |  項 演算子 項 演算子 項 演算子 項  | ....

ですが、これは

  式     :  項  |  式 演算子 項

と書けます。


No.14510

Re:記憶させる2
投稿者---あかま(2004/06/07 02:15:29)


>お願いします、教えてください。
ワタシが全部書いちゃうと意味無いですよね。
その上であなたのソースを直しつつ、できるかぎりやり方を書いてるのですが。
質問したあと、回答とソース読んでますか?
ワタシが直したソースが意味不明ならそう書いていただければもっと詳しく説明するのですが、
全然関係ない方向にソースを壊されちゃうとどうしていいやら。

>追加とありますが、どのようにしたらいいんですか?
ソースの
//ここからトークンのパターンにしたがってモニョモニョな処理
    
//モニョモニョ終了
ってところに追加するんです。
>パターンごとにやるべき順番や処理
を。

で、おさらい。前に投稿したソースで
"a=12"の入力なら
token[0].name="a"
token[0].value='V'

token[1].name="="
token[1].value='S'

token[2].name="12"
token[2].value='N'

がtoken[]に格納されています。とりあえず実行して確認してください。
あと書いてないけどiにはトークンの数3が格納されています。


入力パターンとしては次のようなのがありましたね。
a
a + 1
a = 5
a = 5 + 1
あとは上の4パターンで適宜、変数と数値や演算子が置き換わるぐらいです。
泥臭いけど一つずつ場合分けしていきましょう。

1.i=1のとき
a
のパターンしかないので
printVar(token[0].name);
でいけるはずです。

2.i=3のとき
a + 1
a = 5
の2パターンあります。
そこでtoken[1].valueを見て、どちらのパターンか判断できます。
判断の仕方は
token[].value='S'なら'='
token[].value='O'なら演算子です。

a = 5のパターンならsetVar(token[0].name,token[2].name);でできるはずです。
a + 1のパターンならaの値を取り出す関数を作るなりなんなりして"aの値+atoi(token[2].name)"を表示します。

これは適宜a + bや1 + 3などに置き換わるわけですが、変数か数値かの判断は
token[].value='N'なら数値
token[].value='V'なら変数
です。これはあなたが考えた立派なロジックです。しっかり使ってやってください。

そして残り
3.i=5のときは…
という感じでやってください。



No.14512

Re:記憶させる2
投稿者---gammd(2004/06/07 10:21:19)


ありがとうございます。
じっくり、考えてやってみます。