Home > other >  Expected expression and undeclared identifier error
Expected expression and undeclared identifier error

Time:10-07

When I initialize a pointer to a struct variable all in one line, I get error: expected expression, but if I define the variable before without the declaration it works. I want to define all the struct pointers in one line, without doing a forward declaration first, because if not then my file will get pretty long.

Any suggestions on how I can fix these issues? Or is there no way to circumvent this issue?

...
//a Node class is defined before, similar to a Node in a linked list

struct Node *buildast(struct Node *t) {
  int tag = node_get_tag(t);

  switch (tag) {
      //i dont want to keep declaring my variables likes below
      struct Node *root;
      struct Node *everything_else;
    
    case NODE_translation_unit:
      //To fix my issue, I declared my variables before
      root = node_alloc_str_copy(AST_ROOT, node_get_str(t));
      everything_else = node_get_kid(t, 0);
      node_add_kid(root, everything_else);
      return buildast(everything_else);

    case NODE_definition: 
        //i want to define my struct pointert to a Node in
        //one line like below but get an error
        //when I try to use the below variable later, I get an 
        //undeclared identifier to 'child'
       struct Node *child = node_get_kid(t, 0); //this line gives an error
       if (node_get_num_kids(child) <= 1) {
        node_add_kid(t, child);
        return buildast(child);
       }
       
       ...

CodePudding user response:

This is a problem:

case NODE_definition: 
   struct Node *child = node_get_kid(t, 0);

Because you're applying a label to a declaration. A label can only be applied to a statement.

A simple way to do this without restructuring is to add a null statement right after the case label:

case NODE_definition: 
   ;
   struct Node *child = node_get_kid(t, 0);

Or use a compound statement:

case NODE_definition: 
{
   struct Node *child = node_get_kid(t, 0);
    ...
}

Generally speaking however your code would be cleaner by putting any declarations before the switch so you don't need to define anything inside of it and worry about these types of issues.

CodePudding user response:

Supposing that this ...

When I initialize a pointer to a struct variable all in one line, I get error: expected expression, but if I define the variable before without the declaration it works.

... is intended to describe the error flagged for this ...

    case NODE_definition: 
        //i want to define my struct pointert to a Node in
        //one line like below but get an error
        //when I try to use the below variable later, I get an 
        //undeclared identifier to 'child'
       struct Node *child = node_get_kid(t, 0); //this line gives an error

... you have misunderstood the nature of the problem. And if indeed the error message emitted for that was "expected expression" then you should switch to a better compiler, because that diagnostic is extremely misleading.

Contrast with GCC's diagnostic for the same line:

t.c:11:13: error: a label can only be part of a statement and a declaration is not a statement
             struct node *child = node_get_kid(t, 0);

If you rely on a previous declaration of variable child, then the what's left ...

             child = node_get_kid(t, 0);

... is a statement, and therefore can be labelled. Although it is in fact an expression statement, consisting of an expression, all other kinds of statements are also allowed there -- a break; statement, for example. It is not true that an expression is required.

As for using the variable later, a variable declaration is scoped to the innermost block (if any) containing it, which in this case is the switch body. If you want to use the variable outside the switch then you must declare it before the switch (not just before the case label):

  struct Node *child;

  switch (tag) {

    // ...

    case NODE_definition: 
        child = node_get_kid(t, 0);

    // ...
  }

  // you can still use 'child' here

If you only want it for the one case, then you can insert it into a block (a.k.a. a compound statement):

  switch (tag) {

    // ...

    case NODE_definition: {
        struct Node *child = node_get_kid(t, 0);

        // ...

        // the above declaration of 'child' is in scope (only) up to this point
    } 
  • Related