Logo  

CS456 - Systems Programming

Displaying exercises/e7/solution/parse.c

#include "main.h"

extern int _line;
extern struct cur_tok _cur;

value_t *newvalue(value_dt type, void *value)
{
  value_t *v = malloc(sizeof(value_t));
  v->type = type;
  v->any = value;
  return v;
}

pair_t *newpair(char *name, value_t *v)
{
  pair_t *p = malloc(sizeof(pair_t));
  p->name = name;
  p->v = *v;
  p-> next = NULL;
  return p;
}

value_t *parse_array(void)
{
  long len = 0;
  array_t *a = malloc(sizeof(array_t));
  value_t *v;

  a->length = 0;
  a->a = NULL;

  do {
    // Putting this in here Allows a hanging , prior to ]:
    if (accept(T_CBRAC)) return newvalue(DT_ARRAY, a);

    if ((v = parse_value()) == NULL) return NULL;

    if (a->length == 0) a->a = v;
    else {
      a->a = realloc(a->a, sizeof(value_t) * (a->length+1));
      a->a[a->length] = *v;
    }
    a->length++;
  } while (accept(T_COMMA));

  if (accept(T_CBRAC)) return newvalue(DT_ARRAY, a);
  fprintf(stderr,"Missing closing ] in input on line %d\n", _line);
  return NULL;
}

pair_t *parse_pair(void)
{
  char *name;
  value_t *v;

  // TODO: Add support for identifiers as keys:
  if (_cur.tok != T_STRING) {
    fprintf(stderr,"Invalid key in key/value pair on line %d\n", _line);
    return NULL;
  }
  name = strdup(_cur.buf);
  match(_cur.tok);

  if (!accept(T_COLON)) {
    fprintf(stderr,"Missing : in key/value pair on line %d\n", _line);
    return NULL;
  }

  if ((v = parse_value()) == NULL) {
    fprintf(stderr,"Missing value in key/value pair on line %d\n", _line);
    return NULL;
  }

  return newpair(name, v);
}

value_t *parse_object(void)
{
  pair_t *o = NULL, *p, *e;

  do {
    // Putting this here allows a hanging comma at end of object:
    if (accept(T_CCBRACE)) return newvalue(DT_OBJECT, o);

    if ((p = parse_pair()) == NULL) return NULL;
    if (o == NULL) e = o = p;
    else {
      e->next = p;
      e = p;
    }
  } while(accept(T_COMMA));

  if (accept(T_CCBRACE)) return newvalue(DT_OBJECT, o);
  fprintf(stderr,"Missing } for object on line %d\n", _line);
  return NULL;
}

value_t *parse_value(void)
{
  value_t *v;

  switch(_cur.tok) {
    case T_NUMBER:
      v = newvalue(DT_NUMBER, NULL);
      v->n = _cur.val;
      match(_cur.tok);
      return v;
    case T_STRING:
      v = newvalue(DT_STRING, strdup(_cur.buf));
      match(_cur.tok);
      return v;
    case T_TRUE:
      match(_cur.tok);
      return newvalue(DT_TRUE, NULL);
    case T_FALSE:
      match(_cur.tok);
      return newvalue(DT_FALSE, NULL);
    case T_NULL:
      match(_cur.tok);
      return newvalue(DT_NULL, NULL);
    case T_OBRAC:
      match(_cur.tok);
      return parse_array();
    case T_OCBRACE:
      match(_cur.tok);
      return parse_object();
    default:
      fprintf(stderr,"Unknown token %d on line %d\n", _cur.tok, _line);
      return NULL;
  }
}