We can also add a constructor for this variation.

    1. lval* lval_qexpr(void) {
    2. lval* v = malloc(sizeof(lval));
    3. v->type = LVAL_QEXPR;
    4. v->count = 0;
    5. v->cell = NULL;
    6. return v;
    7. }
    1. void lval_del(lval* v) {
    2. case LVAL_NUM: break;
    3. case LVAL_SYM: free(v->sym); break;
    4. /* If Qexpr or Sexpr then delete all elements inside */
    5. case LVAL_QEXPR:
    6. case LVAL_SEXPR:
    7. for (int i = 0; i < v->count; i++) {
    8. lval_del(v->cell[i]);
    9. }
    10. free(v->cell);
    11. break;
    12. free(v);
    13. }

    Using these simple changes we can update our reading function lval_read to be able to read in Q-Expressions. Because we reused all the S-Expression data fields for our Q-Expression type, we can also reuse all of the functions for S-Expressions such as lval_add. Therefore to read in Q-Expressions we just need to add a special case for constructing an empty Q-Expression to lval_read just below where we detect and create empty S-Expressions from the abstract syntax tree.

    1. if (strcmp(t->children[i]->contents, "(") == 0) { continue; }
    2. if (strcmp(t->children[i]->contents, ")") == 0) { continue; }
    3. if (strcmp(t->children[i]->contents, "}") == 0) { continue; }
    4. if (strcmp(t->children[i]->contents, "{") == 0) { continue; }

    Because there is no special method of evaluating Q-Expressions, we don’t need to edit any of the evaluation functions. Our Q-Expressions should be ready to try. Compile and run the program. Try using them as a new data type and ensure they are not evaluated.