Parcel/code/src/linker.c

111 lines
4.0 KiB
C

#include <parcel.h>
#include <ast.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// pac_copy_empty_rules_from_ast_to_grammar: Creates a grammar corresponding to the AST,
// not copying the variants and their items, but just the rules and their names.
void pac_copy_empty_rules_from_ast_to_grammar(pac_grammar_s *grammar, pac_ast_s *ast)
{
for(usz_t rule_index = 0; rule_index < grammar->num_rules; ++rule_index)
{
pac_ast_rule_s ast_rule = ast->rules[rule_index];
pac_rule_s *rule = &grammar->rules[rule_index];
usz_t len_rule_name = strlen(ast_rule.name);
rule->name = malloc(len_rule_name + 1);
pac_memory_copy(rule->name, ast_rule.name, len_rule_name);
rule->name[len_rule_name] = 0x00;
}
}
pac_set_e pac_convert_ast_set_to_grammar_set(pac_ast_set_e set)
{
switch(set)
{
case PAC_AST_SET_RUNE: return PAC_SET_RUNE;
case PAC_AST_SET_WORD: return PAC_SET_WORD;
case PAC_AST_SET_INTEGER: return PAC_SET_INTEGER;
case PAC_AST_SET_FLOAT: return PAC_SET_FLOAT;
}
return PAC_SET_INVALID;
}
pac_rule_s * pac_find_rule(pac_grammar_s *grammar, char *name)
{
for(usz_t index = 0; index < grammar->num_rules; ++index)
{
if(!strcmp(grammar->rules[index].name, name))
return &grammar->rules[index];
}
printf("Couldn't find refernced rule: %s\n", name);
return NULL;
}
void pac_copy_single_variant(pac_grammar_s *grammar, pac_variant_s *variant, pac_ast_variant_s *ast_variant)
{
variant->num_items = ast_variant->num_items;
variant->items = malloc(sizeof(pac_item_s) * variant->num_items);
for(usz_t item_index = 0; item_index < variant->num_items; ++item_index)
{
pac_ast_item_s ast_item = ast_variant->items[item_index];
pac_item_s *item = &variant->items[item_index];
switch(ast_item.type)
{
case PAC_AST_ITEM_INVALID:
{
item->type = PAC_ITEM_INVALID;
} break;
case PAC_AST_ITEM_LITERAL:
{
item->type = PAC_ITEM_LITERAL;
item->data.literal.length = ast_item.data.literal.length;
item->data.literal.string = ast_item.data.literal.string; // TODO: Copy this into a grammar-owned arena!
} break;
case PAC_AST_ITEM_REFERENCE:
{
item->type = PAC_ITEM_REFERENCE;
item->data.reference = pac_find_rule(grammar, ast_item.data.reference.name);
} break;
case PAC_AST_ITEM_SET:
{
item->type = PAC_ITEM_SET;
item->data.set = pac_convert_ast_set_to_grammar_set(ast_item.data.set);
} break;
}
}
}
void pac_copy_variants_and_link_references(pac_grammar_s *grammar, pac_ast_s *ast)
{
grammar->num_rules = ast->num_rules;
for(usz_t rule_index = 0; rule_index < ast->num_rules; ++rule_index)
{
pac_ast_rule_s ast_rule = ast->rules[rule_index];
pac_rule_s *rule = &grammar->rules[rule_index];
rule->num_variants = ast_rule.num_variants;
rule->variants = malloc(sizeof(pac_variant_s) * rule->num_variants);
for(usz_t variant_index = 0; variant_index < rule->num_variants; ++variant_index)
{
pac_copy_single_variant(grammar, &rule->variants[variant_index], &ast_rule.variants[variant_index]);
}
}
}
pac_grammar_s pac_link_grammar(pac_ast_s ast)
{
pac_grammar_s grammar;
grammar.num_rules = ast.num_rules;
grammar.rules = malloc(sizeof(pac_rule_s) * ast.num_rules);
pac_copy_empty_rules_from_ast_to_grammar(&grammar, &ast);
pac_copy_variants_and_link_references(&grammar, &ast);
return grammar;
}