Ejemplo n.º 1
0
/* Load an ID node.
 * IDs are indicated by the keyword id followed by the ID name, all contained
 * within parentheses. For example:
 *    (id foo)
 *
 * The ( and id keyword must have been parsed before this is called.
 */
static ast_t* get_id(build_parser_t* builder, ast_t* existing_ast)
{
  assert(builder != NULL);

  if(existing_ast != NULL)
  {
    ast_free(existing_ast);
    build_error(builder, "Seen ID not first in node");
    return NULL;
  }

  ast_token_id id = get_token(builder);

  if(id != AT_ID && id != AT_STRING)
  {
    build_error(builder, "ID name expected");
    return NULL;
  }

  ast_t* ast = ast_token(builder->token);
  ast_setid(ast, TK_ID);
  save_token(builder);

  if(get_token(builder) != AT_RPAREN)
  {
    build_error(builder, "Close paren expected for ID");
    ast_free(ast);
    return NULL;
  }

  return ast;
}
Ejemplo n.º 2
0
/* Load a type description.
 * A type description is the type AST node contained in square brackets.
 * The leading [ must have been loaded before this is called.
 */
static ast_t* get_type(build_parser_t* builder, ast_t* parent)
{
  if(parent == NULL)
  {
    build_error(builder, "Type with no containing node");
    return NULL;
  }

  if(ast_type(parent) != NULL)
  {
    build_error(builder, "Node has multiple types");
    return NULL;
  }

  return get_nodes(builder, AT_RSQUARE);
}
Ejemplo n.º 3
0
/* Load node attributes, if any.
 * Attributes are a list of keywords, each prefixed with a colon, following a
 * node name. For example:
 *    seq:scope
 *
 * The node name must have been parsed before calling this, but not the colon.
 */
static ast_t* get_attributes(build_parser_t* builder, ast_t* node)
{
  assert(builder != NULL);

  while(peek_token(builder) == AT_LBRACE)
  {
    get_token(builder);

    if(get_token(builder) != AT_ID)
    {
      build_error(builder, "Expected attribute in {}");
      return NULL;
    }

    const char* attr = token_string(builder->token);

    if(strcmp("scope", attr)==0)
    {
      if(!scope_attribute(builder, node))
        return NULL;
    }
    else if(strcmp("def", attr) == 0)
    {
      if(!def_attribute(builder, node))
        return NULL;
    }
    else if(strcmp("dataref", attr) == 0)
    {
      if(!dataref_attribute(builder, node))
        return NULL;
    }
    else
    {
      build_error(builder, "Unrecognised attribute \"%s\"", attr);
      return NULL;
    }

    if(get_token(builder) != AT_RBRACE)
    {
      build_error(builder, "Expected } after attribute %s", attr);
      return NULL;
    }
  }

  return node;
}
Ejemplo n.º 4
0
/**
 * An element it the list has a bad type.
 * Used by i18n_message. 
 */
ERL_NIF_TERM list_element_error(ErlNifEnv* env, 
    const ERL_NIF_TERM list, int32_t num) {
    return build_error(env, 
        enif_make_tuple3(env,
            enif_make_atom(env, "bad_element"),
            enif_make_tuple2(env,
                enif_make_atom(env, "list"),
                list),
            enif_make_tuple2(env,
                enif_make_atom(env, "index"),
                enif_make_int(env, (int) num))
            ));
}
Ejemplo n.º 5
0
/**
 * Convert an UErrorCode to an atom. 
 */
ERL_NIF_TERM parse_error(ErlNifEnv* env, UErrorCode status, 
        UParseError* e) {
    return build_error(env, 
        enif_make_tuple3(env,
            enif_make_atom(env, u_errorName(status)),
            enif_make_tuple2(env,
                enif_make_atom(env, "line"),
                enif_make_int(env, (int) e->line)),
            enif_make_tuple2(env,
                enif_make_atom(env, "offset"),
                enif_make_int(env, (int) e->offset))
            ));
}
Ejemplo n.º 6
0
// Process all our sub-tree references
static bool process_refs(build_parser_t* builder)
{
  assert(builder != NULL);
  assert(builder->defs != NULL);

  for(builder_ref_t* p = builder->refs; p != NULL; p = p->next)
  {
    assert(p->name != NULL);
    assert(p->node != NULL);

    ast_t* subtree = (ast_t*)symtab_find(builder->defs, p->name, NULL);

    if(subtree == NULL)
    {
      build_error(builder, "Attribute {def %s} not found", p->name);
      return false;
    }

    if(p->symtab == NULL)
    {
      // Set node data
      ast_setdata(p->node, subtree);
    }
    else
    {
      // Add subtree to node's symtab
      symtab_t* symtab = ast_get_symtab(p->node);
      assert(symtab != NULL);
      if(!symtab_add(symtab, p->symtab, subtree, SYM_NONE))
      {
        build_error(builder, "Duplicate name %s in symbol table", p->name);
        return false;
      }
    }
  }

  return true;
}
Ejemplo n.º 7
0
/* Process a dataref attribute.
* The dataref keyword should be found before calling this, but nothing else.
*/
static bool dataref_attribute(build_parser_t* builder, ast_t* node)
{
  assert(builder != NULL);

  if(get_token(builder) != AT_ID)
  {
    build_error(builder, "Expected {dataref name}");
    return false;
  }

  const char* ref_name = stringtab(token_string(builder->token));
  add_subtree_ref(builder, node, ref_name, NULL);
  return true;
}
Ejemplo n.º 8
0
// Add a sub-tree name definition
static bool add_subtree_name(build_parser_t* builder, const char* name,
  ast_t* subtree)
{
  assert(builder != NULL);
  assert(builder->defs != NULL);

  if(!symtab_add(builder->defs, name, subtree, SYM_NONE))
  {
    build_error(builder, "Multiple {def %s} attributes", name);
    return false;
  }

  return true;
}
Ejemplo n.º 9
0
/**
 * An element it the list has a bad type.
 * Used by i18n_message. 
 */
ERL_NIF_TERM list_element_error(ErlNifEnv* env, UErrorCode status, 
    const ERL_NIF_TERM list, int32_t num, 
        const char *pszFile, long lLine) {
    return build_error(env, 
        enif_make_tuple4(env,
            enif_make_atom(env, "bad_element"),
            enif_make_atom(env, u_errorName(status)),
            enif_make_tuple2(env,
                enif_make_atom(env, "list"),
                list),
            enif_make_tuple2(env,
                enif_make_atom(env, "index"),
                enif_make_int(env, (int) num))
            ),
        pszFile, lLine);
}
Ejemplo n.º 10
0
/**
 * Pass an error to Erlang code.
 * Error as a string will be converted to an atom.
 */
ERL_NIF_TERM make_error(ErlNifEnv* env, const char* code, 
        const char *pszFile, long lLine) {
    return build_error(env,
        enif_make_atom(env, code),
        pszFile, lLine);
}
Ejemplo n.º 11
0
// Load a sequence of nodes until the specified terminator is found
static ast_t* get_nodes(build_parser_t* builder, ast_token_id terminator)
{
  assert(builder != NULL);

  ast_t* ast = NULL;
  ast_t* last_child = NULL;

  while(true)
  {
    ast_token_id id = get_token(builder);
    ast_t* child = NULL;
    bool is_type = false;

    if(id == terminator)
    {
      if(ast == NULL)
        build_error(builder, "Syntax error");

      if(ast_id(ast) == TK_MINUS && ast_childcount(ast) == 1)
        ast_setid(ast, TK_UNARY_MINUS);

      return ast;
    }

    if(id == AT_ID)
      id = keyword_replace(builder);

    switch(id)
    {
      case AT_LPAREN:
        child = get_nodes(builder, AT_RPAREN);
        break;

      case AT_LSQUARE:
        child = get_type(builder, ast);
        is_type = true;
        break;

      case AT_ERROR:  // Propogate
        break;

      case AT_STRING:
      case AT_TOKEN:
        child = ast_token(builder->token);
        save_token(builder);
        get_attributes(builder, child);
        break;

      case AT_ID:
        if(strcmp("id", token_string(builder->token)) == 0)
          return get_id(builder, ast);

        build_error(builder, "Unrecognised identifier \"%s\"",
          token_string(builder->token));
        break;

      default:
        build_error(builder, "Syntax error");
        break;
    }

    if(child == NULL)
    {
      // An error occurred and should already have been reported
      ast_free(ast);
      return NULL;
    }

    if(ast == NULL)
    {
      ast = child;
      last_child = NULL;
    }
    else if(is_type)
    {
      ast_settype(ast, child);
    }
    else
    {
      if(last_child == NULL)
        ast_add(ast, child);
      else
        ast_add_sibling(last_child, child);

      last_child = child;
    }
  }
}
Ejemplo n.º 12
0
/**
 * Pass an error to Erlang code.
 * Error as a string will be converted to an atom.
 */
ERL_NIF_TERM make_error(ErlNifEnv* env, const char* code) {
    return build_error(env,
        enif_make_atom(env, code));
}