示例#1
0
文件: parser.cpp 项目: helgefmi/Toy
Statement *ParserContext::parse_statement() {
    Statement *statement = 0;
    switch (curtok()->type()) {
        case tok_while: {
            statement = parse_while();
            break;
        }
        case tok_if: {
            statement = parse_if();
            break;
        }
        case tok_return: {
            statement = parse_return();
            eat_token(tok_semicolon);
            break;
        }
        case tok_def: {
            statement = parse_def();
            break;
        }
        default: {
            Expression *expression = parse_expression();
            if (expression) {
                statement = new ExpressionStatement(expression);
                eat_token(tok_semicolon);
            } else {
                throw UnexpectedToken("parse_statement", curtok());
            }
            break;
        }
    }
    return statement;
}
示例#2
0
// Parse a statement.
//
//    stmt ::= def-stmt | expr-stmt
Tree*
parse_stmt(Parser& p) {
  if (Tree* t = parse_def(p))
    return t;
  if (Tree* t = parse_expr(p))
    return t;
  return nullptr;
}
示例#3
0
int main(int argc, char *argv[])
{

	if(argc < 3) {
		fprintf(stderr, "Usage:\n%s fontdesc.def outfile.iff\n", argv[0]);
		return 0;
	}

	def = file_new(argv[1], 0);
	if(!def) {
		fprintf(stderr, "Can't find font definition '%s'\n", argv[1]);
		return 1;
	}
	file_load(def);
	if(!def->buf) {
		file_free(def);
		fprintf(stderr, "Not enough memory to load %s\n", argv[1]);
		return 2;
	}

	if(!parse_def()) {
		file_free(def);
		return 1;
	}

	font = iff_new(argv[2], MAKE_ID('F','O','N','T'));
	if(!font) {
		file_free(def);
	}

	iff_newchunk(font, MAKE_ID('N','A','M','E'));
	iff_writechunkdata(font, name, strlen(name)+1);
	iff_endchunk(font);

	iff_newchunk(font, MAKE_ID('F','I','L','E'));
	iff_writechunkdata(font, file, strlen(file)+1);
	iff_endchunk(font);

	iff_newchunk(font, MAKE_ID('A','U','T','H'));
	iff_writechunkdata(font, author, strlen(author)+1);
	iff_endchunk(font);

	parse_letters();

	iff_close(font);
	file_free(def);
	return 0;
}
示例#4
0
文件: peg.c 项目: ctelfer/catlib
/* TODO: boundary check str_spn() calls to check against overflows. */
int peg_parse(struct peg_grammar_parser *pgp, struct peg_grammar *peg,
	      const char *string, uint len, int flags)
{
	struct peg_cursor pc = { 0, 1 };
	int start;
	int rv;

	if ( !initialized ) {
		cset_init_accept(cs_space, " \t\r\n");
		cset_init_accept(cs_eol, "\r\n");
		cset_init_accept(cs_id_start,
			         "abcdefghijklmnopqrstuvwxyz"
			         "ABCDEFGHIJKLMNOPQRSTUVWXYZ_");
		cset_init_accept(cs_id_cont,
			         "abcdefghijklmnopqrstuvwxyz"
			         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
			         "_0123456789");
		cset_init_accept(cs_special, "nrt'\"[]\\");
		cset_init_accept(cs_digit0to2, "012");
		cset_init_accept(cs_digit0to7, "01234567");
		cset_init_reject(cs_ccode, "\"\'/{}\r\n");
		cset_rem(cs_ccode, '\0');
		initialized = 1;
	}

	peg->nodes = NULL;
	peg->max_nodes = 0;
	peg->num_nodes = 0;
	peg->num_tokens = 0;
	peg->start_node = -1;
	peg->dynamic = 1;

	pgp->input = string;
	pgp->input_len = len;
	pgp->len = 0;
	pgp->nlines = 1;
	pgp->flags = flags;
	pgp->peg = peg;
	pgp->err = 0;
	pgp->eloc = pc;

	skip_space(pgp, &pc);

	rv = parse_def(pgp, &pc, &start);
	if ( rv <= 0 ) {
		peg_free_nodes(peg);
		return rv;
	}

	peg->start_node = start;

	while ( pc.pos < len ) {
		rv = parse_def(pgp, &pc, NULL);
		if ( rv < 0 ) {
			peg_free_nodes(peg);
			return -1;
		}
		if ( rv == 0 )
			break;
	}

	if ( check_unresolved_ids(pgp) < 0 ) {
		peg_free_nodes(peg);
		return -1;
	}

	pgp->len = pc.pos;
	pgp->nlines = pc.line;

	return 1;
}
示例#5
0
void rrd_graph_script(
    int argc,
    char *argv[],
    image_desc_t *const im,
    int optno)
{
    int       i;

    /* and now handle the things*/
    parsedargs_t pa;
    initParsedArguments(&pa);

    /* loop arguments */
    for (i = optno; i < argc; i++) {
	/* release parsed args - avoiding late cleanups*/
	freeParsedArguments(&pa);
	/* processed parsed args */
	if (parseArguments(argv[i],&pa)) {
	  return; }

        /* dumpArguments(&pa); */
	/* now let us handle the field based on the first command or cmd=...*/
	char*cmd=NULL;
	/* and try to get via cmd */
	char* t=getKeyValueArgument("cmd",255,&pa);
	if (t) {
	  cmd=t;
	} else if ((t=getKeyValueArgument("pos0",255,&pa))) {
	  cmd=t;
	} else {
	  rrd_set_error("no command set in argument %s",pa.arg_orig);
	  freeParsedArguments(&pa);
	  return;
	}

	/* convert to enum but handling LINE special*/
	enum gf_en gf = (enum gf_en) -1;
	gf=gf_conv(cmd);
	if ((int)gf == -1) {
	  if (strncmp("LINE",cmd,4)==0) {
	    gf=GF_LINE;
	    addToArguments(&pa,NULL,"linewidth",cmd+4,0);
	  } else {
	    rrd_set_error("'%s' is not a valid function name in %s", cmd,pa.arg_orig );
	    return;
	  }
	}
	/* now we can handle the commands */
	int r=0;
	switch (gf) {
	case GF_XAXIS:     r=parse_axis(gf,&pa,im); break;
	case GF_YAXIS:     r=parse_axis(gf,&pa,im); break;
	case GF_DEF:       r=parse_def(gf,&pa,im); break;
	case GF_CDEF:      r=parse_cvdef(gf,&pa,im); break;
	case GF_VDEF:      r=parse_cvdef(gf,&pa,im); break;
	case GF_LINE:      r=parse_line(gf,&pa,im); break;
	case GF_AREA:      r=parse_area(gf,&pa,im); break;
	case GF_PRINT:     r=parse_gprint(gf,&pa,im); break;
	case GF_GPRINT:    r=parse_gprint(gf,&pa,im); break;
	case GF_COMMENT:   r=parse_comment(gf,&pa,im); break;
	case GF_HRULE:     r=parse_hvrule(gf,&pa,im); break;
	case GF_VRULE:     r=parse_hvrule(gf,&pa,im); break;
	case GF_STACK:     r=parse_stack(gf,&pa,im); break;
	case GF_TICK:      r=parse_tick(gf,&pa,im); break;
	case GF_TEXTALIGN: r=parse_textalign(gf,&pa,im); break;
	case GF_SHIFT:     r=parse_shift(gf,&pa,im); break;
	case GF_XPORT:     r=parse_xport(gf,&pa,im); break;
	  /* unsupported types right now */
  }
	/* handle the return error case */
	if (r) { freeParsedArguments(&pa); return;}
	/* check for unprocessed keyvalue args */
	char *s;
	if ((s=checkUnusedValues(&pa))) {
	  /* set error message */
	  rrd_set_error("Unused Arguments \"%s\" in command : %s",s,pa.arg_orig);
	  free(s);
	  /* exit early */
	  freeParsedArguments(&pa);
	  return;
	}
    }
    /* finally free arguments */
    freeParsedArguments(&pa);
}
示例#6
0
文件: profile.c 项目: Maijin/radare2
R_API int r_reg_set_profile_string(RReg *reg, const char *str) {
	char *tok[PARSER_MAX_TOKENS];
	char tmp[128];
	int i, j, l;
	const char *p = str;

	if (!reg || !str) {
		return false;
	}

	// Same profile, no need to change
	if (reg->reg_profile_str && !strcmp (reg->reg_profile_str, str)) {
		return true;
	}

	// we should reset all the arenas before setting the new reg profile
	r_reg_arena_pop (reg);
	// Purge the old registers
	r_reg_free_internal (reg, true);
	r_reg_arena_shrink (reg);

	// Cache the profile string
	reg->reg_profile_str = strdup (str);

	// Line number
	l = 0;
	// For every line
	do {
		// Increment line number
		l++;
		// Skip comment lines
		if (*p == '#') {
			const char *q = p;
			while (*q != '\n') {
				q++;
			}
			reg->reg_profile_cmt = r_str_appendlen (
				reg->reg_profile_cmt, p, (int)(q - p) + 1);
			p = q;
			continue;
		}
		j = 0;
		// For every word
		while (*p) {
			// Skip the whitespace
			while (*p == ' ' || *p == '\t') {
				p++;
			}
			// Skip the rest of the line is a comment is encountered
			if (*p == '#') {
				while (*p != '\n') {
					p++;
				}
			}
			// EOL ?
			if (*p == '\n') {
				break;
			}
			// Gather a handful of chars
			// Use isgraph instead of isprint because the latter considers ' ' printable
			for (i = 0; isgraph ((const unsigned char)*p) && i < sizeof (tmp) - 1;) {
				tmp[i++] = *p++;
			}
			tmp[i] = '\0';
			// Limit the number of tokens
			if (j > PARSER_MAX_TOKENS - 1) {
				break;
			}
			// Save the token
			tok[j++] = strdup (tmp);
		}
		// Empty line, eww
		if (j) {
			// Do the actual parsing
			char *first = tok[0];
			// Check whether it's defining an alias or a register
			const char *r = (*first == '=')
				? parse_alias (reg, tok, j)
				: parse_def (reg, tok, j);
			// Clean up
			for (i = 0; i < j; i++) {
				free (tok[i]);
			}
			// Warn the user if something went wrong
			if (r) {
				eprintf ("%s: Parse error @ line %d (%s)\n",
					__FUNCTION__, l, r);
				//eprintf ("(%s)\n", str);
				// Clean up
				r_reg_free_internal (reg, false);
				return false;
			}
		}
	} while (*p++);
	reg->size = 0;
	for (i = 0; i < R_REG_TYPE_LAST; i++) {
		RRegSet *rs = &reg->regset[i];
		//eprintf ("* arena %s size %d\n", r_reg_get_type (i), rs->arena->size);
		reg->size += rs->arena->size;

	}
	// Align to byte boundary if needed
	//if (reg->size & 7) {
	//	reg->size += 8 - (reg->size & 7);
	//}
	//reg->size >>= 3; // bits to bytes (divide by 8)
	r_reg_fit_arena (reg);
	// dup the last arena to allow regdiffing
	r_reg_arena_push (reg);
	r_reg_reindex (reg);
	// reset arenas
	return true;
}
示例#7
0
R_API int r_reg_set_profile_string(RReg *reg, const char *str) {
	char *tok[PARSER_MAX_TOKENS];
	char tmp[128];
	int i, j, l;
	const char *p = str;

	if (!reg || !str)
		return false;

	// Same profile, no need to change
	if (reg->reg_profile_str && !strcmp (reg->reg_profile_str, str))
		return true;

	// Purge the old registers
	r_reg_free_internal (reg);

	// Cache the profile string
	reg->reg_profile_str = strdup (str);

	// Line number
	l = 0;
	// For every line
	do {
		// Increment line number
		l++;
		// Skip comment lines
		if (*p == '#') {
			while (*p != '\n')
				p++;
			continue;
		}
		j = 0;
		// For every word
		while (*p) {
			// Skip the whitespace
			while (*p == ' ' || *p == '\t')
				p++;
			// Skip the rest of the line is a comment is encountered
			if (*p == '#')
				while (*p != '\n')
					p++;
			// EOL ?
			if (*p == '\n')
				break;
			// Gather a handful of chars
			// Use isgraph instead of isprint because the latter considers ' ' printable
			for (i = 0; isgraph ((const unsigned char)*p) && i < sizeof(tmp) - 1;)
				tmp[i++] = *p++;
			tmp[i] = '\0';
			// Limit the number of tokens 
			if (j > PARSER_MAX_TOKENS - 1)
				break;
			// Save the token
			tok[j++] = strdup (tmp);
		}
		// Empty line, eww
		if (j) {
			// Do the actual parsing 
			char *first = tok[0];
			// Check whether it's defining an alias or a register
			const char *r = (*first == '=') ?
				parse_alias (reg, tok, j) :
				parse_def (reg, tok, j);
			// Clean up
			for (i = 0; i < j; i++)
				free(tok[i]);
			// Warn the user if something went wrong
			if (r) {
				eprintf("%s: Parse error @ line %d (%s)\n",
					__FUNCTION__, l, r);
				//eprintf ("(%s)\n", str);
				// Clean up
				r_reg_free_internal (reg);
				return false;
			}
		}
	} while (*p++);

	// Align to byte boundary if needed
	if (reg->size&7)
		reg->size += 8 - (reg->size&7);
	reg->size >>= 3; // bits to bytes (divide by 8)
	r_reg_fit_arena (reg);
	return true;
}
示例#8
0
/* Actions to be taken when a whole line of input has been processed */
ELEMENT *
end_line (ELEMENT *current)
{
  char *end_command = 0;
  enum command_id end_id;

  // 2621
  /* If empty line, start a new paragraph. */
  if (last_contents_child (current)
      && last_contents_child (current)->type == ET_empty_line)
    {
      debug ("END EMPTY LINE");
      if (current->type == ET_paragraph) /* 2625 */
        {
          ELEMENT *e;
          /* Remove empty_line element. */
          e = pop_element_from_contents (current);

          current = end_paragraph (current);

          /* Add empty_line to higher-level element. */
          add_to_element_contents (current, e);
        }
      //else if () // in menu_entry_description
      else if (!in_no_paragraph_contexts (current_context ()))
        {
          current = end_paragraph (current);
        }
    }

  // 2667
  /* The end of the line of a menu. */
  else if (current->type == ET_menu_entry_name
           || current->type == ET_menu_entry_node)
    {
      ELEMENT *end_comment;
      int empty_menu_entry_node = 0;

      if (current->type == ET_menu_entry_node)
        {
          ELEMENT *last = last_contents_child (current);

          if (current->contents.number > 0
              && (last->cmd == CM_c || last->cmd == CM_comment))
            {
              end_comment = pop_element_from_contents (current);
            }

          /* If contents empty or is all whitespace. */
          if (current->contents.number == 0
              || (current->contents.number == 1
                  && last->text.end > 0
                  && !last->text.text[strspn (last->text.text, 
                                              whitespace_chars)]))
            {
              empty_menu_entry_node = 1;
              if (end_comment)
                add_to_element_contents (current, end_comment);
            }
        }

      // 2689
      /* Abort the menu entry if there is no destination node given. */
      if (empty_menu_entry_node || current->type == ET_menu_entry_name)
        {
        }
      else // 2768
        {
          debug ("MENU ENTRY END LINE");
          current = current->parent;
          current = enter_menu_entry_node (current);
          if (end_comment)
            add_to_element_contents (current, end_comment);
        }
    }

  /* Is it a def line 2778 */
  else if (current->parent && current->parent->type == ET_def_line)
    {
      enum element_type def_command;

      if (pop_context () != ct_def)
        {
          abort ();
        }

#if 0
      /* current->parent is a ET_def_line, and current->parent->parent
         the def command. */
      def_command = current->parent->parent->cmd;
      // strip a trailing x
      parse_def (def_command, current->contents);
#endif

      current = current->parent->parent;
      current = begin_preformatted (current);

    }

  // 2872
  /* End of a line starting a block. */
  else if (current->type == ET_block_line_arg)
    {
      enum context c;
      // pop and check context_stack
      c = pop_context ();
      if (c != ct_line)
        {
          // bug
          abort ();
        }

      // 2881
      if (current->parent->cmd == CM_multitable)
        {
          /* Parse prototype row */
          // But not @columnfractions, I assume?
        }

      if (current->parent->cmd == CM_float) // 2943
        {
        }
      current = current->parent; //2965

      /* Don't consider empty argument of block @-command as argument,
         reparent them as contents. */
      if (current->args.list[0]->contents.number > 0
          && current->args.list[0]->contents.list[0]->type
             == ET_empty_line_after_command)
        {
          ELEMENT *e;
          e = current->args.list[0]->contents.list[0];
          insert_into_contents (current, e, 0);
          // TODO: Free lists?
          current->args.number = 0;
        }

      if (command_flags(current) & CF_blockitem) // 2981
        {
          if (current->cmd == CM_enumerate)
            {
            }
          else if (item_line_command (current->cmd)) // 3002
            {
              // check command_as_argument registered in 'extra', and
              // that it accepts arguments in braces
            }

          if (current->cmd == CM_itemize) // 3019
            {
              // check that command_as_argument is alone on the line
            }

          // check if command_as_argument isn't an accent command

          /* 3052 - if no command_as_argument given, default to @bullet for
             @itemize, and @asis for @table. */

          {
            ELEMENT *bi = new_element (ET_before_item);
            add_to_element_contents (current, bi);
            current = bi;
          }
        } /* CF_blockitem */

      // 3077
      if (command_flags(current) & CF_menu)
        {
          /* Start reading a menu.  Processing will continue in
             handle_menu in menus.c. */

          ELEMENT *menu_comment = new_element (ET_menu_comment);
          add_to_element_contents (current, menu_comment);
          current = menu_comment;
          debug ("MENU COMMENT OPEN");
          push_context (ct_preformatted);
        }
      current = begin_preformatted (current);
    }

  /* after an "@end verbatim" 3090 */
  else if (current->contents.number
           && last_contents_child(current)->type == ET_empty_line_after_command
    /* The Perl version gets the command with the 'command' key in 'extra'. */
           && contents_child_by_index(current, -2)
           && contents_child_by_index(current, -2)->cmd == CM_verbatim)
    {
      // I don't know what this means.  raw command is @html etc.?
      /*
     if we are after a @end verbatim, we must restart a preformatted if needed,
     since there is no @end command explicitly associated to raw commands
     it won't be done elsewhere.
      */

      current = begin_preformatted (current);
    }


  /* if it's a misc line arg 3100 */
  else if (current->type == ET_misc_line_arg)
    {
      int cmd_id, arg_type;
      enum context c;

      isolate_last_space (current, 0);

      current = current->parent;
      cmd_id = current->cmd;
      if (!cmd_id)
        abort ();

      arg_type = command_data(cmd_id).data;
       
      /* Check 'line' is top of the context stack */
      c = pop_context ();
      if (c != ct_line)
        {
          /* error */
          abort ();
        }

      // 3114
      debug ("MISC END %s", command_data(cmd_id).cmdname);

      if (arg_type > 0)
        {
          /* arg_type is number of args */
          // parse_line_command_args
          // save in 'misc_args' extra key
        }
      else if (arg_type == MISC_text) /* 3118 */
        {
          char *text;
         
          /* argument string has to be parsed as Texinfo. This calls convert in 
             Common/Text.pm on the first element of current->args. */
          /* however, this makes it impossible to decouple the parser and 
             output stages...  Any use of Texinfo::Convert is problematic. */

          if (current->args.number > 0)
            text = text_convert (current->args.list[0]);
          else
            text = "foo";

          if (!strcmp (text, ""))
            {
              /* 3123 warning - missing argument */
              abort ();
            }
          else
            {
              if (current->cmd == CM_end) /* 3128 */
                {
                  char *line = text;

                  /* Set end_command - used below. */
                  end_command = read_command_name (&line);

                  /* Check argument meets format of a Texinfo command
                     (alphanumberic character followed by alphanumeric 
                     characters or hyphens. */

                  /* Check if argument is a block Texinfo command. */
                  end_id = lookup_command (end_command);
                  if (end_id == -1 || !(command_data(end_id).flags & CF_block))
                    {
                      /* error - unknown @end */
                    }
                  else
                    {
                      debug ("END BLOCK %s", end_command);
                      /* 3140 Handle conditional block commands (e.g.  
                         @ifinfo) */

                      /* If we are in a non-ignored conditional, there is not
                         an element for the block in the tree; it is recorded 
                         in the conditional stack.  Pop it and check it is the 
                         same as the one given in the @end line. */

                      if (command_data(end_id).data == BLOCK_conditional)
                        {
                          if (conditional_number > 0)
                            {
                              enum command_id popped;
                              popped = pop_conditional_stack ();
                              if (popped != end_id)
                                abort ();
                            }
                        }
                    }
                }
              else if (current->cmd == CM_include) /* 3166 */
                {
                  debug ("Include %s", text);
                  input_push_file (text);
                }
              else if (current->cmd == CM_documentencoding)
                /* 3190 */
                {
                }
              else if (current->cmd == CM_documentlanguage)
                /* 3223 */
                {
                }
            }
        }
      else if (current->cmd == CM_node) /* 3235 */
        {
          int i;
          ELEMENT *arg;
          ELEMENT *first_arg;
          /* Construct 'nodes_manuals' array.  This would be an 'extra' 
             reference to an array that doesn't exist anywhere else. */

          /* This sets the 'node_content' and 'normalized' keys on each element 
             in 'nodes_manuals'. */
          //parse_node_manual ();
          
          /* In Perl a copy of the argument list is taken and the empty space 
             arguments are removed with trim_spaces_comment_from_content. */
          first_arg = current->args.list[0];
          arg = new_element (ET_NONE);
          arg->parent_type = route_not_in_tree;
          for (i = 0; i < first_arg->contents.number; i++)
            {
              if (first_arg->contents.list[i]->type
                    != ET_empty_spaces_after_command
                  && first_arg->contents.list[i]->type != ET_spaces_at_end)
                {
                  /* FIXME: Is this safe to serialize? */
                  /* For example, if there are extra keys in the elements under 
                     each argument?  They may not be set in a copy.
                     Hopefully there aren't many extra keys set on commands in 
                     node names. */
                  add_to_element_contents (arg, first_arg->contents.list[i]);
                }
            }
          add_extra_key_contents (current, "node_content", arg);

          /* Also set 'normalized' here.  The normalized labels are actually 
             the keys of "labels_information($parser)". */

          /*Check that the node name doesn't have a filename element for 
            referring to an external manual (_check_internal_node), and that it 
            is not empty (_check_empty_node).  */
          //check_node_label ();

          /* This sets 'node_content' and 'normalized' on the node, among
             other things (which were already set in parse_node_manual). */
          register_label (current, arg);

          current_node = current;
        }
      else if (current->cmd == CM_listoffloats) /* 3248 */
        {
        }
      else
        {
          /* All the other "line" commands" */
        }

      current = current->parent; /* 3285 */
      if (end_command) /* Set above */
        {
          /* more processing of @end */
          ELEMENT *end_elt;

          debug ("END COMMAND %s", end_command);

          /* Reparent the "@end" element to be a child of the block element. */
          end_elt = pop_element_from_contents (current);

          /* 3289 If not a conditional */
          if (command_data(end_id).data != BLOCK_conditional)
            {
              ELEMENT *closed_command;
              /* This closes tree elements (e.g. paragraphs) until we reach
                 end_command.  It can print an error if another block command
                 is found first. */
              current = close_commands (current, end_id,
                              &closed_command, 0); /* 3292 */
              if (!closed_command)
                abort (); // 3335

              close_command_cleanup (closed_command);
              // 3301 INLINE_INSERTCOPYING
              add_to_element_contents (closed_command, end_elt); // 3321
              // 3324 ET_menu_comment
              if (close_preformatted_command (end_id))
                current = begin_preformatted (current);
            }
        } /* 3340 */
      else
        {
          if (close_preformatted_command (cmd_id))
            current = begin_preformatted (current);
        }

      /* 3346 included file */

      /* 3350 */
      if (cmd_id == CM_setfilename && (current_node || current_section))
        {
          /* warning */
          abort ();
        }
      /* 3355 columnfractions */
      else if (cmd_id == CM_columnfractions)
        {
          ELEMENT *before_item;
          // check if in multitable

          // pop and check context stack

          current = current->parent;
          before_item = new_element (ET_before_item);
          add_to_element_contents (current, before_item);
          current = before_item;
        }
      else if (command_data(cmd_id).flags & CF_root) /* 3380 */
        {
          current = last_contents_child (current);
          
          /* 3383 Destroy all contents (why do we do this?) */
          while (last_contents_child (current))
            destroy_element (pop_element_from_contents (current));

          /* Set 'associated_section' extra key for a node. */
          if (cmd_id != CM_node && cmd_id != CM_part)
            {
              if (current_node)
                {
                  if (!lookup_extra_key (current_node, "associated_section"))
                    {
                      add_extra_key_element
                        (current_node, "associated_section", current);
                      add_extra_key_element
                        (current, "associated_node", current_node);
                    }
                }

              // "current parts" - 3394

              current_section = current;
            }
        } /* 3416 */
    }


  // something to do with an empty line /* 3419 */

  //if () /* 'line' or 'def' at top of "context stack" */
    {
      /* Recurse. */
    }
  return current;
} /* end_line 3487 */