3

文字列を計算するためのキー要素の解析済みツリーを本質的に構築する yacc や bison などを含むこの質問には、多くのオーバーヘッドがあります。しかし、それはすべて正しく機能しています。私はかなり自信を持っています。問題は、1 つのしつこいリンク リストにあります。

前述したように、私は一種の「計算機」を使用していますが、この計算機は、リンクされたリスト内に格納されている変数を受け入れることになっています。(add 1 4) のようなフレーズは問題​​なく機能しますが、((let (firstvar 2)) (add firstvar 4)) のようなものを試すと難しいのは、シンボル リスト (1 のリスト) を通過することになっています。この場合) firstvar の値 (作成され、インスタンス化され、add ステートメントの前に let ステートメントで割り当てられたもの) を見つけて、それをチェーンに入れます。

つまり、問題は、「symbolList」をさまざまなオペランドに渡そうとすると、構造体が奇妙で紛らわしい方法で上書きされることです。

まず、.h の主な共用体:

typedef struct
{
    double value;
} NUMBER_AST_NODE;

typedef struct
{ 
    char *name;
} SYMBOL_AST_NODE;

typedef struct
{
   char *name;
   struct ast_node *op1;
   struct ast_node *op2;
} FUNCTION_AST_NODE;

typedef struct ast_symbol
{
    char *name; //symbol name
    struct ast_node *data;

    struct ast_symbol *next;
    struct ast_symbol *parent;
} AST_SYMBOL;

typedef struct ast_node
{
    AST_NODE_TYPE type;
    union
    {
        NUMBER_AST_NODE number;
        FUNCTION_AST_NODE function;
        SYMBOL_AST_NODE symbol;
    } data;

    AST_SYMBOL *symbolList;    
} AST_NODE; 

さて、ツリーが部分的に作成されたと仮定すると、問題は「symbolList」がツリーの最上位のメンバーにのみ関連付けられていることです...そのため、それを子に渡す必要があります (つまり、オペランド 1 &オペランド 2) を使用して、symbolList にアクセスできるようにし、関数に渡される変数を適切に変換できるようにします。

だから、私はこのような再帰呼び出しを行っています:

void translate(AST_NODE *p)
{
  //recursive infix traversal.
  if(p->type == NUM_TYPE){
      printf("%6f",(double) p->data.number.value);
  }
  else if (p->type == SYM_TYPE){
      resolveSymbol(p->symbolList, p->data.symbol.name); //this goes and finds the variable, and it does it correctly IF it has the symbolList!
  }
  else if(p->type == FUNC_TYPE){
          printf("( ");

          p->data.function.op1->symbolList = p->symbolList; //passing the symbolList onward

          translate(p->data.function.op1);
          printf( " %c ",resolveOp(resolvdfunc)); //ignore this, it's just displaying the char like '+' for add

          p->data.function.op2->symbolList = p->symbolList; //passing the symbolList onward
          translate(p->data.function.op2);
          printf(" )");
    }
  }

   if (!p)
      return;
} 

よし、例として。2 番目のオペランドの symbolList の受け渡しをコメントアウトするとします。次に、 ((let (a 2)) (add a 4)) のようなステートメントは問題なく機能します。しかし、明らかに、 ((let (a 2)) (add 4 a)) を試してみると、2番目のオペランドが「a」変数にアクセスできないため、機能しません。

問題は、現在、その 2 番目の symbolList をコメントアウトせずに渡すと、最初のオペランドが上書きされ、symbolList にアクセスできなくなることです。

私はこれが理にかなっていることを願っています....それは私を狂気に駆り立てています。

ありがとう。

編集: 9:22 -- これが resolveSymbol コードです (要求どおり)...

void resolveSymbol(AST_SYMBOL *p, char *name)
{
    if (p == NULL)
        yyerror("No such symbol exists");
    else if (strcmp(p->name, name) == 0) {
        translate(p->data);
    }
    else
        resolveSymbol(p->next, name);
}
4

1 に答える 1

1

おそらく問題とは関係ありませんが(ただし、解決が容易になる可能性があります)、一般に、再帰関数に引数を、関連のないデータ構造にぶら下げるよりも、引数として渡す方が理にかなっています。

void translate(AST_NODE *p, AST_SYMBOL *symbols) {
  if(p->type == NUM_TYPE) {
    printf("%6f",(double) p->data.number.value);
  } else if (p->type == SYM_TYPE) {
    resolveSymbol(symbols, p->data.symbol.name);
  } else if(p->type == FUNC_TYPE) {
    printf("( ");
    translate(p->data.function.op1, symbols);
    printf( " %c ", resolveOp(resolvdfunc)); //ignore this, it's just displaying the char like '+' for add
    translate(p->data.function.op2, symbols);
    printf(" )");
  }
} 

これにより、symbolListフィールドを完全に削除し、変更せずにASTデータ構造をトラバースできます。

于 2012-10-30T17:38:22.573 に答える