include “%{file}.h” include <stdlib.h> include <stdio.h> include <stdint.h> include <limits.h> include <alloca.h> include <string.h>

static const unsigned int %{prefix}states[] = { % table.each do |state|

{ %{action_for(state)} },

% end };

ifndef %{upper_prefix}INITSTACK # define %{upper_prefix}INITSTACK 64 endif

ifndef %{upper_prefix}ALLOC # define %{upper_prefix}ALLOC malloc endif

ifndef %{upper_prefix}FREE # define %{upper_prefix}FREE free endif

struct %{prefix}stack_element {

%{stype}* val;
unsigned int state;

};

define %{upper_prefix}PUSH_STACK(stack, v, s) do { \

int err; \
if(stack.current + 1 > stack.max) \
{ \
  if((err = %{prefix}resize_stack(&stack)) != 0) \
    return err; \
} \
stack.elements[stack.current].val = val; \
stack.elements[stack.current].state = s; \

} while(0)

define %{upper_prefix}POP_STACK(stack, out) do { \

out = stack.elements + stack.current; \
stack.current -= 1; \

} while(0)

const char* %{prefix}token_string(%{terminal_type} token) {

switch(token)
{

% grammar.terminals.each do |terminal|

case %{token_prefix}%{terminal.name}:
  return %{terminal.to_s.inspect};

% end

}

return "(unknown)";

}

%{prefix}pstate* %{prefix}state_new() {

%{prefix}pstate* stack = %{upper_prefix}ALLOC(sizeof(%{prefix}pstate));
if(stack != NULL)
{
  stack->max = %{upper_prefix}INITSTACK;
  stack->elements = %{upper_prefix}ALLOC(sizeof(struct %{prefix}stack_element) * stack->max);
  stack->current = 0;
  stack->free = 1;
}

return stack;

}

void %{prefix}state_delete(%{prefix}pstate* stack) {

stack->current = 0;
stack->max = 0;
stack->free = 0;

if(stack->free)
{
  %{upper_prefix}FREE(stack->elements);
  %{upper_prefix}FREE(stack);
}

stack->elements = 0;

}

int %{prefix}resize_stack(%{prefix}pstate* stack) {

void* body;
int new_max;

if(stack->current + 1 > stack->max)
{
  new_max = stack->max * 2;
}
else if((stack->current / 2) < stack->max)
{
  new_max = stack->max / 2;
}
else
{
  return 0;
}

body = %{upper_prefix}ALLOC(sizeof(struct %{prefix}stack_element) * new_max);

if(body == NULL)
{
  return ENOMEM;
}

memcpy(body, stack->elements, sizeof(struct %{prefix}stack_element) * stack->current);

if(stack->free)
{
  %{upper_prefix}FREE(stack->elements);
}

stack->elements = body;
stack->max = new_max;

return 0;

}

int %{prefix}parse_push(%{prefix}pstate* stack int token,

%{upper_prefix}STYPE* val%{parse_params})

{

unsigned int action;
%{prefix}stack_element* current_state;

current_state = stack.elements + stack.current - 1;

if(token > %{upper_prefix}TERMINALS || token < 0)
  %{prefix}abort;

get_action:

action = states[current_state->state][token];

if(action < %{upper_prefix}STATES)
{
  %{upper_prefix}PUSH_STACK(stack, val, action - 1);
  return %{upper_prefix}PUSH_MORE;
}

switch(action)
{
case 0:
  %{prefix}error;
  break;
case %{table.size + 1}:
  stack.current = 0;
  return 0;

% productions.each_with_index do |(label, size, block), i|

case %{i + table.size + 2}: { // %{i}
  %{upper_prefix}STYPE* %{prefix}vals[%{size}];
  %{upper_prefix}STYPE* %{prefix}out;

% size.times do |e|

%{upper_prefix}POP_STACK(stack, %{prefix}vals[%{e}]);

% end

  %{prefix}out = %{prefix}vals[0];
  current_state = stack.elements + stack.current - 1;

  do {
    {{= cify_block(block) }}
  } while(0);

  token  = %{symbols[label.name]};
  action = states[current_state->state][token];
  %{upper_prefix}PUSH_STACK(stack, %{prefix}out, action);
  break;
}

% end

}

return %{upper_prefix}PUSH_MORE;

}

int %{prefix}parse_pull(%{parse_params}) {

%{prefix}pstate stack;
int token;
unsigned int action;
%{upper_prefix}STYPE val;
%{prefix}stack_element* current_state;

stack.max      = %{upper_prefix}INITSTACK;
stack.elements = alloca(sizeof(struct %{prefix}stack_element) * stack.max);
stack.current  = 0;
stack.free     = 0;

%{upper_prefix}PUSH_STACK(stack, NULL, 1);

while(stack.current > 0)
{
  token = %{prefix}lex(&val%{params});
  %{prefix}parse_push(&stack, token, &val%{parse_params});
}

}