Beispiel #1
0
bool GrammarRead(Grammar *grammar, const char *fileName)
{
    // Read the file.
    grammar->fileName = fileName;
    FILE *srcFile = fopen(fileName, "r");
    if (srcFile == NULL)
    {
        AllocSprintf(&grammar->errMsg, "can't open '%s'", fileName);
        return false;
    }
    
    // Go through it line by line.
    grammar->lineNo = 1;
    char line[4096];
    while (fgets(line, sizeof(line), srcFile))
    {
        // Remove comments.
        char *commentPos = strstr(line, "//");
        if (commentPos != NULL)
        {
            *commentPos = 0;
        }
        
        // Remove trailing whitespace.
        StringStripEnd(line);
        
        // Skip empty lines.
        if (line[0] != 0)
        {
            // Is it a definition line?
            if (isalpha(line[0]))
            {
                // Parse a definition.
                if (!GrammarParseDefinition(grammar, line))
                    goto grErrExit;
            }
            else if (isspace(line[0]))
            {
                // Parse an option.
                if (!GrammarParseOption(grammar, line))
                    goto grErrExit;
            }
            else
            {
                // Unexpected character.
                AllocSprintf(&grammar->errMsg, "unexpected character in %s line %d: '%s'", fileName, grammar->lineNo, line);
                goto grErrExit;
            }
        }

        grammar->lineNo++;
    }
    
    return true;

grErrExit:
    fclose(srcFile);
    return false;
}
Beispiel #2
0
bool GrammarParseCharSet(Grammar *grammar, GrammarItem *item, char **pos)
{
    // A bitset of allowed characters.
    uint8_t charSet[MAX_CHARSET / 8];
    bool positiveSet = true;

    // Skip the leading brace character.
    if (**pos == '{')
    {
        (*pos)++;
    }

    // Is this a positive or negative set?
    if (**pos == '^')
    {
        positiveSet = false;
        (*pos)++;
        memset(charSet, 0xff, sizeof(charSet));
    }
    else
    {
        positiveSet = true;
        memset(charSet, 0, sizeof(charSet));
    }

    // Add/remove each of the specified characters.
    int ch;
    while (**pos != '}' && **pos != 0 && GrammarParseCharacter(pos, &ch))
    {
        if (ch < MAX_CHARSET)
        {
            if (positiveSet)
            {
                // Add it to the bitset.
                charSet[ch/8] = charSet[ch/8] | (1<<(ch%8));
            }
            else
            {
                // Remove it from the bitset.
                charSet[ch/8] = charSet[ch/8] & ~(1<<(ch%8));
            }
        }
    }

    // Did the character set finish suitably?
    if (**pos != '}')
    {
        AllocSprintf(&grammar->errMsg, "character set is missing a closing brace in line %d\n", grammar->lineNo);
        return false;
    }

    (*pos)++;

    // Copy the result to the item.
    item->charSet = calloc(MAX_CHARSET / 8, sizeof(uint8_t));
    memcpy(item->charSet, charSet, MAX_CHARSET/8);

    return true;
}
Beispiel #3
0
bool GrammarParseOption(Grammar *grammar, char *line)
{
    char *pos = line;

    SkipWhitespace(&pos);

    // Create an option node.
    GrammarOption *opt = calloc(1, sizeof(*opt));
    if (opt == NULL)
    {
        AllocSprintf(&grammar->errMsg, "out of memory");
        return false;
    }

    // Add it to the end of the list.
    GrammarDefinition *def = grammar->lastDef;
    if (def == NULL)
    {
        AllocSprintf(&grammar->errMsg, "option before definition, line %d", grammar->lineNo);
        free(opt);
        return false;
    }

    if (def->firstOption == NULL)
    {
        def->firstOption = opt;
        def->lastOption = opt;
    }
    else
    {
        def->lastOption->nextOption = opt;
        def->lastOption = opt;
    }

    opt->nextOption = NULL;
    opt->firstItem = NULL;
    opt->lastItem = NULL;

    // Parse the items.
    bool ok = false;
    while (GrammarParseItem(grammar, opt, &pos, &ok))
    {
    }

    return ok;
}
Beispiel #4
0
bool GrammarParseDefinition(Grammar *grammar, char *line)
{
    // Create a definition node.
    GrammarDefinition *def = calloc(1, sizeof(*def));
    if (def == NULL)
    {
        AllocSprintf(&grammar->errMsg, "out of memory");
        return false;
    }

    // Add it to the end of the list.
    if (grammar->firstDef == NULL)
    {
        grammar->firstDef = def;
        grammar->lastDef = def;
    }
    else
    {
        grammar->lastDef->nextDefinition = def;
        grammar->lastDef = def;
    }

    def->nextDefinition = NULL;
    def->firstOption = NULL;
    def->lastOption = NULL;
    char *pos = line;
    def->name = GrammarParseIdentifier(&pos);

    // There should only be a colon after the identifier.
    SkipWhitespace(&pos);
    if (*pos != ':')
    {
        AllocSprintf(&grammar->errMsg, "colon expected in definition, line %d", grammar->lineNo);
        return false;
    }

    pos++;
    if (*pos != 0)
    {
        AllocSprintf(&grammar->errMsg, "unexpected text after definition, line %d", grammar->lineNo);
        return false;
    }

    return true;
}
Beispiel #5
0
bool GrammarRead(Grammar *grammar, const char *fileName)
{
    // Read the file.
    grammar->fileName = fileName;
    if (!ReadFile(&grammar->src, &grammar->errMsg, fileName))
        return false;
    
    // Go through it line by line.
    grammar->lineNo = 1;
    char *line;
    char *nextLine = grammar->src;
    while (ReadLine(&line, &nextLine))
    {
        // Remove comments.
        char *commentPos = strstr(line, "//");
        if (commentPos != NULL)
        {
            *commentPos = 0;
        }
        
        // Remove trailing whitespace.
        StringStripEnd(line);
        
        // Skip empty lines.
        if (line[0] != 0)
        {
            // Is it a definition line?
            if (isalnum(line[0]))
            {
                // Parse a definition.
                if (!GrammarParseDefinition(grammar, line))
                    return false;
            }
            else if (isspace(line[0]))
            {
                // Parse an option.
                if (!GrammarParseOption(grammar, line))
                    return false;
            }
            else
            {
                // Unexpected character.
                AllocSprintf(&grammar->errMsg, "unexpected character in %s line %d: '%s'", fileName, grammar->lineNo, line);
                return false;
            }
        }

        grammar->lineNo++;
    }
    
    return true;
}
Beispiel #6
0
bool GrammarParseString(Grammar *grammar, GrammarItem *item, char **pos)
{
    // Skip the leading quote character.
    if (**pos == '\'')
    {
        (*pos)++;
    }

    // Gather characters until we reach a closing single quote or the end of the string.
    int ch;
    int i = 0;
    char str[MAX_STRING+1];
    while (GrammarParseCharacter(pos, &ch) && i < MAX_STRING)
    {
        str[i] = ch;
        i++;
    }

    // Null terminate the string.
    str[i] = 0;

    // Did the string finish suitably?
    if (**pos == '\'')
    {
        (*pos)++;
        item->token = strdup(str);

        return true;
    }
    else if (**pos == 0)
    {
        AllocSprintf(&grammar->errMsg, "string is missing a closing quote in line %d\n", grammar->lineNo);
        return false;
    }

    AllocSprintf(&grammar->errMsg, "string terminates strangely in line %d\n", grammar->lineNo);
    return false;
}
Beispiel #7
0
bool GrammarParseItem(Grammar *grammar, char *str)
{
    AllocSprintf(&grammar->errMsg, "unimplemented");
    return false;
}
Beispiel #8
0
bool GrammarParseOption(Grammar *grammar, char *line)
{
    AllocSprintf(&grammar->errMsg, "unimplemented");
    return false;
}
Beispiel #9
0
bool GrammarParseItem(Grammar *grammar, GrammarOption *option, char **pos, bool *ok)
{
    *ok = true;

    // Are we at the end of the line?
    SkipWhitespace(pos);
    if (**pos == 0)
    {
        // There are no more items.
        return false;
    }

    // Create an item node.
    GrammarItem *item = calloc(1, sizeof(*item));
    if (item == NULL)
    {
        AllocSprintf(&grammar->errMsg, "out of memory");
        return false;
    }

    // Add it to the end of the list.
    if (option->firstItem == NULL)
    {
        option->firstItem = item;
        option->lastItem = item;
    }
    else
    {
        option->lastItem->nextItem = item;
        option->lastItem = item;
    }

    item->nextItem = NULL;
    item->repeated = false;
    item->definitionName = NULL;
    item->token = NULL;
    item->charSet = NULL;

    // Is it repeated?
    bool repeated = false;
    char ch = **pos;
    if (ch == '[')
    {
        repeated = true;
        (*pos)++;
    }

    // What kind of token is next?
    switch (ch)
    {
    case 0:
        AllocSprintf(&grammar->errMsg, "missing item after '[' in line %d\n", grammar->lineNo);
        *ok = false;
        break;

    case '\'':
        *ok = GrammarParseString(grammar, item, pos);
        break;

    case '{':
        *ok = GrammarParseCharSet(grammar, item, pos);
        break;

    default:
        if (isalpha(ch))
        {
            // Parse a definition name.
            item->definitionName = GrammarParseIdentifier(pos);
        }
        else
        {
            // It's something unknown.
            AllocSprintf(&grammar->errMsg, "unknown character in line %d\n", grammar->lineNo);
            *ok = false;
        }
        break;
    }

    // If it was repeated, make sure we have a closing square bracket.
    if (repeated)
    {
        if (**pos != ']')
        {
            AllocSprintf(&grammar->errMsg, "expected closing ']' after repeated term in line %d\n", grammar->lineNo);
            *ok = false;
        }

        item->repeated = true;
    }

    // If we're failing out deallocate the item.
    if (!*ok)
    {
        free(item);
        return false;
    }

    return true;
}