Search code examples
semanticsjavacc

Record the types of a comma seperated list of identifiers?


For semantic analysis I need to put the identifiers and their types into a custom Hash Map. But given the following grammar rules and implementation it is beyond me how I could record all identifiers declared by the ident_list below.

Grammar rules:

var_decl := var ident_list:type ( , ident_list:type )* ; 
ident_list := identifier ( , identifier )*
type := integer | boolean | real | string | void

The implementation in the jjt file is as follows:

void var_decl() #void : {Token t; String[] name;}
{
  <VAR> ident_list() <COLON> type() #var_decl(2) 
    (<COMMA> ident_list() <COLON> type() #var_decl_ext(2))* <SEMIC>
}


void ident_list() : {}
{
  identifier() (<COMMA> identifier())*
}


String identifier() #ID : { Token t; }
{
  t=<ID> { jjtThis.value = t.image; return t.image; }
}


String type() #TYPE : { Token t; }
{
  t=<INTEGER> {jjtThis.value = t.image; return t.image; } |
  t=<BOOLEAN> {jjtThis.value = t.image; return t.image; } |
  t=<REAL> {jjtThis.value = t.image; return t.image; } |
  t=<STRING> {jjtThis.value = t.image; return t.image; } |
  t=<VOID> {jjtThis.value = t.image; return t.image; }
}

If it were just a singular identifier in each var_decl I can see how to get the necessary information, but how would you pass a list of one or more identifiers back up to var_decl for assignment? Is this realistically achievable in jjtree/javacc?


Solution

  • Yes. You can return a list of identifiers from ident_list like this:

    List<String> ident_list() : {
        List<String> ids = new ArrayList<String>() ;
        String id ; }
    {
      id = identifier() { ids.add(id) ; }
      (<COMMA> id = identifier() { ids.add(id) ; } )*
      {return ids ; }
    }
    

    Now refactor var_decl a bit. What you do with the map is up to you, but I would stash it in in a node.

    void var_decl() #var_decl : {
        HashMap<String, String> decls = new HashMap<String, String>() ;
    }
    {
      <VAR> one_var_decl(decls)
      ( <COMMA> one_var_decl(decls) )* <SEMIC>
      { jjThis.decls = decls ; }
    }
    

    And build the map in the new nonterminal.

    void one_var_decl(HashMap<String, String> decls) #void :
    {
        List<String> ids ;
        String ty ;
    }
    {
        ids = ident_list() <COLON> ty = type()
        { for( String id <- ids ) {
               // You may want to emit an error or warning here if there is a duplication.
               decls.add(id, ty) ; } }
    }