示例#1
0
static void skip_to_endln(state_t* state)
{
    char c;
    
    while (ppimpl_has_input(state))
    {
        c = ppimpl_get_input(state);
        if (c == '\n')
            return;
    }
}
示例#2
0
///
/// Performs preprocessing using the internally
/// constructed state object.
///
void ppimpl_process(state_t* state)
{
    char c;
    match_t* m;
    bool reprocess = false;
    size_t i;
    scope_t* current;

    while (ppimpl_has_input(state))
    {
        // Fetch a character from the input.
        c = ppimpl_get_input(state);

        // Push it onto the output.
        list_append(&state->cached_output, (void*)c);

        // Update string tracking states.
        ppimpl_track_strings(state);

        // If we are in a single or double string, no matching
        // operations can be performed.
        if (state->in_single_string || state->in_double_string)
            continue;

        // We keep process once unless we're asked to restart
        // by a match.  This is used when a match changes the
        // handlers (such as appending a new handler or removing
        // an old one), and we need to restart the matching process.
        do
        {
            reprocess = false;

            // Iterate through all of our match handlers.
            for (i = 0; i < list_size(&state->handlers); i++)
            {
                m = (match_t*)list_get_at(&state->handlers, i);

                // Test for a match and if so, handle it.
                if (ppimpl_match_test(state, m))
                {
                    // Remove the characters from the cached input
                    // depending on the match text length.
                    list_delete_range(&state->cached_output,
                                      list_size(&state->cached_output) - blength(m->text.ref),
                                      list_size(&state->cached_output) - 1);

                    // Reset the printing index.
                    state->print_index = 0;

                    // Call the match handler.
                    m->handler(state, m, &reprocess);
                    if (reprocess)
                        break;
                }
            }
        }
        while (reprocess);
    }

    // We have finished processing; everything is stored in the cached output,
    // so now we push everything that was in the cached output.
    while (list_size(&state->cached_output) > 0)
        state->output((char)list_extract_at(&state->cached_output, 0));
}
示例#3
0
///
/// Checks to see if the current output cache
/// has a match against a specified match definition.
///
bool ppimpl_match_test(state_t* state, match_t* match)
{
    size_t i;
    int32_t j;

    // Check if the output cache is even long enough to hold
    // the match.
    if (list_size(&state->cached_output) < (size_t)blength(match->text.ref))
        return false;

    // Check each character until we find one that doesn't
    // match, going backwards through the list (remember that
    // we're matching against the end of the list).
    for (i = 0; i < (size_t)blength(match->text.ref); i++)
    {
        if (!match->case_insensitive)
        {
            if ((char)list_get_at(&state->cached_output, list_size(&state->cached_output) - i - 1) !=
                    (char)match->text.ref->data[blength(match->text.ref) - i - 1])
                return false;
        }
        else
        {
            if (tolower((char)list_get_at(&state->cached_output, list_size(&state->cached_output) - i - 1)) !=
                    tolower((char)match->text.ref->data[blength(match->text.ref) - i - 1]))
                return false;
        }
    }

    // We have a match, ensure that it is at the start of the line
    // if required.
    if (match->line_start_only)
    {
        // We have to make sure that we only have spaces or tabs between
        // the first character of the text and a \n or the start of the output.
        j = (int32_t)(list_size(&state->cached_output) - (size_t)blength(match->text.ref) - 1);
        while (j >= 0)
        {
            switch ((char)list_get_at(&state->cached_output, j))
            {
                case ' ':
                case '\t':
                    // Permitted; continue.
                    break;
                case '\n':
                    // This means that it is at the start of a line.
                    return true;
                default:
                    // Anything else means that it's not at the start.
                    return false;
            }
            j--;
        }

        // If we reach here, check if i == 0, which means that we've
        // matched the start of the input (which also counts as a match).
        if (j <= 0)
            return true;
        else
            assert(false); // Something is not right.
    }

    // We have a match, ensure it is a proper identifier.
    if (match->identifier_only)
    {
        // We have to get the surrounding characters.
        bool has_next = ppimpl_has_input(state);
        bool has_previous = (list_size(&state->cached_output) >= (size_t)blength(match->text.ref) + 1);
        char next;
        char previous;
        bool is_identifier = false;
        if (has_next)
        {
            next = ppimpl_get_input(state);
            list_insert_at(&state->cached_input, (void*)next, 0);
        }
        if (has_previous)
            previous = (char)list_get_at(&state->cached_output, list_size(&state->cached_output) - blength(match->text.ref) - 1);

        // Check to see if the preceeding character (before the
        // match) and the proceeding character (after the match)
        // both isolate this match as an identifier.
        if (has_next && has_previous)
            is_identifier = ppimpl_isolates(next, false) && ppimpl_isolates(previous, true);
        else if (has_next)
            is_identifier = ppimpl_isolates(next, false);
        else if (has_previous)
            is_identifier = ppimpl_isolates(previous, true);
        else
            is_identifier = true;

        return is_identifier;
    }

    // We have a match that can be matched anywhere.
    return true;
}
示例#4
0
static void macro_handle(state_t* state, match_t* match, bool* reprocess)
{
    bstring name;
    bstring temp;
    list_t parameters;
    list_t arguments;
    bool getting_name = true;
    bool getting_parameters = false;
    bool getting_arguments = false;
    struct replace_info* info = match->userdata;
    int i = 0;
    int argument_brackets = 0;
    char c;
    char* start_loc;
    match_t* new_match;
    struct replace_info* new_info;

    // Parse the parameters out of the name.
    list_init(&parameters);
    temp = bfromcstr("");
    for (i = 0; i < blength(info->full); i++)
    {
        c = info->full->data[i];
        if (getting_name)
        {
            if (c == '(')
            {
                getting_name = false;
                getting_parameters = true;
                name = bstrcpy(temp);
                bassigncstr(temp, "");
            }
            else
                bconchar(temp, c);
        }
        else if (getting_parameters)
        {
            if (c == ',' || c == ')')
            {
                btrimws(temp);
                list_append(&parameters, bstrcpy(temp));
                bassigncstr(temp, "");
                if (c == ')')
                {
                    getting_parameters = false;
                    break;
                }
            }
            else
                bconchar(temp, c);
        }
    }

    // Attempt to accept an open bracket.
    c = ppimpl_get_input(state);
    while (c == '\1')
    {
        // Consume macro termination.
        i = 0;
        while (i < strlen("\1MACROTERMINATE\1"))
        {
            if (c != "\1MACROTERMINATE\1"[i++])
                dhalt(ERR_PP_EXPECTED_OPEN_BRACKET, ppimpl_get_location(state));
            c = ppimpl_get_input(state);
        }
        ppimpl_pop_scope(state);
    }
    if (c != '(')
        dhalt(ERR_PP_EXPECTED_OPEN_BRACKET, ppimpl_get_location(state));
    
    // Read arguments.
    getting_arguments = true;
    list_init(&arguments);
    start_loc = ppimpl_get_location(state);
    bassigncstr(temp, "");
    while (ppimpl_has_input(state) && getting_arguments)
    {
        c = ppimpl_get_input(state);

        if (c == '(')
        {
            argument_brackets++;
            bconchar(temp, c);
        }
        else if (c == ')' && argument_brackets != 0)
        {
            argument_brackets--;
            bconchar(temp, c);
        }
        else if (c == ')' && argument_brackets == 0)
        {
            list_append(&arguments, bstrcpy(temp));
            bassigncstr(temp, "");
            getting_arguments = false;
            break;
        }
        else if (c == ',' && argument_brackets == 0)
        {
            list_append(&arguments, bstrcpy(temp));
            bassigncstr(temp, "");
        }
        else
            bconchar(temp, c);
    }
    if (getting_arguments)
        dhalt(ERR_PP_NO_TERMINATING_BRACKET, start_loc);

    // Check to see if the argument count is correct.
    if (list_size(&arguments) > list_size(&parameters))
        dhalt(ERR_PP_TOO_MANY_PARAMETERS, start_loc);
    else if (list_size(&arguments) < list_size(&parameters))
        dhalt(ERR_PP_NOT_ENOUGH_PARAMETERS, start_loc);
    free(start_loc);

    // Create a new scope for macro evaluation.
    ppimpl_push_scope(state, true);

    // Define the new handlers.
    for (i = 0; i < list_size(&parameters); i++)
    {
        new_info = malloc(sizeof(struct replace_info));
        new_info->full = list_get_at(&parameters, i);
        new_info->replacement = list_get_at(&arguments, i);
        if (biseq(new_info->full, new_info->replacement))
        {
            free(new_info);
            continue;
        }
        new_match = malloc(sizeof(match_t));
        new_match->text = bautofree(list_get_at(&parameters, i));
        new_match->handler = replace_handle;
        new_match->line_start_only = false;
        new_match->identifier_only = true;
        new_match->userdata = new_info;
        new_match->case_insensitive = false;
        ppimpl_register(state, new_match);
    }
    
    // Print out the macro evaluation and terminator.
    ppimpl_printf(state, "%s\1MACROTERMINATE\1", info->replacement->data);
}
示例#5
0
static void define_handle(state_t* state, match_t* match, bool* reprocess)
{
    // We need to parse this manually because we're interested in getting
    // the first word and then all of the content until a line that doesn't end
    // with "\".
    bstring name = bfromcstr("");
    bstring word = bfromcstr("");
    bstring definition = bfromcstr("");
    bool getting_word = true;
    bool getting_definition = true;
    bool is_macro = false;
    match_t* new_match;
    struct replace_info* info;

    // Get the first word.
    while (getting_word)
    {
        char c = ppimpl_get_input(state);
        bconchar(word, c);
        if (!is_macro && c != '(')
            bconchar(name, c);
        bltrimws(word);

        // Handle termination.
        if (blength(word) > 0 && (c == ' ' || c == '\t') && !is_macro)
        {
            // End of word.
            btrimws(word);
            btrimws(name);
            getting_word = false;
        }
        else if (blength(word) > 0 && c == '(' && !is_macro)
        {
            // Start of macro.
            is_macro = true;
        }
        else if (blength(word) > 0 && c == '(' && is_macro)
        {
            // Second ( in a macro; error.
            dhalt(ERR_PP_MACRO_MALFORMED, ppimpl_get_location(state));
        }
        else if (blength(word) > 0 && c == ')' && is_macro)
        {
            // End of macro name.
            btrimws(word);
            btrimws(name);
            getting_word = false;
        }
        else if (blength(word) == 0 && c == '\n')
            dhalt(ERR_PP_C_DEFINE_PARAMETERS_INCORRECT, ppimpl_get_location(state));
        else if (blength(word) > 0 && c == '\n')
        {
            // End of word.
            btrimws(word);
            btrimws(name);
            getting_word = false;
            getting_definition = false;
            ppimpl_printf(state, "\n");
        }
    }

    // Get the definition.
    while (getting_definition)
    {
        char c = ppimpl_get_input(state);
        bconchar(definition, c);
        bltrimws(definition);
        
        if (c == '\n')
        {
            if (blength(definition) > 1 && definition->data[blength(definition) - 2] == '\\')
            {
                // Remove the new slash.
                bdelete(definition, blength(definition) - 2, 1);
                ppimpl_oprintf(state, "\n");
            }
            else
            {
                btrimws(definition);
                getting_definition = false;
                ppimpl_printf(state, "\n");
            }
        }
        else if (c == '/' || c == '*')
        {
            if (blength(definition) > 1 && definition->data[blength(definition) - 2] == '/')
            {
                // a line or block comment
                ppimpl_iprintf(state, "/%c", c);
                // remove the slashes
                bdelete(definition, blength(definition) - 2, 2);
                btrimws(definition);
                getting_definition = false;
            }
        }
    }
    
    if (blength(definition) == 0 && !is_macro)
        bassigncstr(definition, "1");
        

    // Create the new replacement handler.
    info = malloc(sizeof(struct replace_info));
    info->full = word;
    info->replacement = definition;
    if (biseq(info->full, info->replacement))
    {
        free(info);
        return;
    }
    new_match = malloc(sizeof(match_t));
    new_match->text = bautofree(name);
    if (is_macro)
        new_match->handler = macro_handle;
    else
        new_match->handler = replace_handle;
    new_match->line_start_only = false;
    new_match->identifier_only = true;
    new_match->userdata = info;
    new_match->case_insensitive = false;
    ppimpl_register(state, new_match);
    *reprocess = true;
}
示例#6
0
static bstring skip_to_endif(state_t* state, bool stop_at_else, bool* stopped_at_else)
{
    char c;
    bool fresh_line = true;
    bstring temp = bfromcstr("");
    bstring temp_output = bfromcstr("");
    bstring output = bfromcstr("");
    int if_open = 1; 
    
    while (ppimpl_has_input(state))
    {
        c = ppimpl_get_input(state);
        switch(c)
        {
            case '#':
            case '.':
                if (!fresh_line)
                {
                    bconchar(output, c);
                    break;
                }
                bassigncstr(temp_output, "#");
                // first skip spaces
                while (ppimpl_has_input(state))
                {
                    c = ppimpl_get_input(state);
                    bconchar(temp_output, c);
                    if (c != ' ' && c != '\t')
                        break;
                }
                // read pp directive
                bassigncstr(temp, "");
                bconchar(temp, c);
                while (ppimpl_has_input(state))
                {
                    c = ppimpl_get_input(state);
                    bconchar(temp_output, c);
                    if (c == ' ' || c == '\t' || c == '\n')
                        break;
                    bconchar(temp, c);
                }
                
                btolower(temp);
                
                if (biseq(temp, bfromcstr("endif")))
                {
                    if_open--;
                    if (if_open == 0)
                    {
                        if (c != '\n') skip_to_endln(state);
                        *stopped_at_else = false;
                        return output;
                    }
                }
                else if (biseq(temp, bfromcstr("if")))
                {
                    if_open++;
                }
                else if (biseq(temp, bfromcstr("else")) && stop_at_else)
                {
                    if (if_open == 1)
                    {
                        if (c != '\n') skip_to_endln(state);
                        *stopped_at_else = true;
                        return output;
                    }
                }
                bconcat(output, temp_output);
                fresh_line = (c == '\n');
                break;
                
            case '\n':
                fresh_line = true;
                bconchar(output, c);
                break;
            case ' ':
            case '\t':
                bconchar(output, c);
                break;
                
            default:
                fresh_line = false;
                bconchar(output, c);
                break;
        }
    }
    
    // No .ENDIF was found.
    dhalt(ERR_PP_ASM_NO_ENDIF_TO_IF, ppimpl_get_location(state));

    // dhalt will trigger before this, but the compiler warns about
    // control potentially reaching the end of this function.
    return NULL;
}