⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.cpp

📁 Code for top down parser in C++
💻 CPP
字号:
//---------------------------------------------------------------------------
//
//  Top-down parser with backtracking for arbitrary context-free grammars
//  Dmitry Brant, Spr 2004
//
//-----------

#include <vcl.h>
#pragma hdrstop

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <stdexcept.h>
#include "grammar.h"
#include "treeform.h"

using std::runtime_error;

bool Traverse(char* input);
unsigned int inputLength, verbosity=0;
Grammar* g;
//---------------------------------------------------------------------------


int main(int argc, char* argv[]){

    g = new Grammar();
    char* inputStr = new char[32768]; //nice, big buffer for input
    char* grammarFile = "grammar.txt";
    memset(inputStr, 0, 32768);
    inputStr[0] = 0;

    try{
        bool doEliminateEpsilon=true, doEliminateUnit=true, doEliminateLeftRecursion=true;

        //what's this? do we have a command line argument?
        if(argc > 1){
            for(int i=1; i<argc; i++){
                if(LowerCase(String(argv[i])) == "-v"){
                    if(i<(argc-1)){ verbosity = atoi(argv[i+1]); i++; }
                }
                else if(LowerCase(String(argv[i])) == "-g"){
                    if(i<(argc-1)){ grammarFile = argv[i+1]; i++; }
                }
                else if(LowerCase(String(argv[i])) == "-ne"){
                    doEliminateEpsilon = false;
                }
                else if(LowerCase(String(argv[i])) == "-nu"){
                    doEliminateUnit = false;
                }
                else if(LowerCase(String(argv[i])) == "-nr"){
                    doEliminateLeftRecursion = false;
                }
                else if(LowerCase(String(argv[i])) == "-na"){
                    doEliminateEpsilon = false;
                    doEliminateUnit = false;
                    doEliminateLeftRecursion = false;
                }
                else{
                    FILE* f = fopen(argv[i], "rb");
                    if(!f) throw runtime_error(("could not open " + String(argv[1]) + " for input").c_str());
                    unsigned int bytesread = fread(inputStr, 1, 32768, f);
                    fclose(f);
                    if(!bytesread) throw runtime_error(("could not read from file " + String(argv[1])).c_str());
                    inputLength = bytesread;
                    printf("Input loaded successfully.\n");
                }
            }
        }

        g->LoadFromFile(grammarFile);
        printf("\nGrammar loaded successfully.\n");

        if(doEliminateEpsilon){
            g->EliminateEpsilonProductions();
            g->SaveToFile("grammar_after_epsilon.txt");
            printf("Epsilon productions eliminated.\n");
        }

        if(doEliminateUnit){
            g->EliminateUnitProductions();
            g->SaveToFile("grammar_after_unit.txt");
            printf("Unit productions eliminated.\n");
        }

        if(doEliminateLeftRecursion){
            g->EliminateLeftRecursion();
            g->SaveToFile("grammar_after_left_recursion.txt");
            printf("Left recursion eliminated.\n");
        }
        
        if(!inputStr[0]){
            printf("\nPlease enter your input string:\n");
            gets(inputStr);
            inputLength = strlen(inputStr);
        }

        if(!inputLength) throw runtime_error("Empty input string");

        //collapse whitespace in string
        int ptr=0, newPtr=0;
        do{
            if((inputStr[ptr] > ' ') || (inputStr[ptr] == 0)){
                inputStr[newPtr++] = inputStr[ptr];
            }
        }while(inputStr[ptr++] != 0);

        //check this out:
        if(Traverse(inputStr)){
            printf("\nString parsed successfully!\n");
        }else{
            throw runtime_error("failed to parse string");
        }

    }catch(exception &e){
        printf("\nParsing failed: %s\n", e.what());
    }catch(...){
        printf("\nUnknown exception.\n");
    }

    delete g;
    delete [] inputStr;
    return 0;
}
//---------------------------------------------------------------------------



void printNodes(TList* nodes, ParseNode* currentNode){
    for(int i=0; i<nodes->Count; i++){
        if(((ParseNode*)nodes->Items[i]) == currentNode){
            printf("[");
            printf(((ParseNode*)nodes->Items[i])->str.c_str());
            printf("]");
        }else
        printf(((ParseNode*)nodes->Items[i])->str.c_str());
        int idx = ((ParseNode*)nodes->Items[i])->index;
        printf(("<" + String(idx) + ">").c_str());
    }
    printf("\n");
}
//---------------------------------------------------------------------------

void printflevel(int level, char* str){
    for(int i=0; i<level; i++) printf("  ");
    printf(str);
}
//---------------------------------------------------------------------------

void DeleteNodeChildren(TList* nodes, ParseNode* node){
    //delete any other nodes whose parent is this node
    for(int i=0; i<nodes->Count; i++){
        ParseNode* otherNode = (ParseNode*)nodes->Items[i];
        if(otherNode->parent == node){
            if(!otherNode->terminal) DeleteNodeChildren(nodes, otherNode);
            int pos = nodes->IndexOf(otherNode);
            delete otherNode;
            nodes->Delete(pos);
            i--;
        }
    }
}
//-----------------------------------------

bool MatchNodeTrace(TList* nodes, char* input){
    int inputPtr=0;
    bool equal = true;
    //delete any other nodes whose parent is this node
    for(int i=0; i<nodes->Count; i++){
        ParseNode* node = (ParseNode*)nodes->Items[i];
        if(node->terminal && (node->str != "")){
            if(node->str != String(input[inputPtr])){
                equal = false; break;
            }
            inputPtr++;
        }
    }
    return equal;
}
//-----------------------------------------



//The traversal procedure:
//an ingenious linked-list design, without recursion.
//Algorithm:
//Wave hands, and sing:
//   "Backtrack, backtrack, search, search, search,
//      "Search, search, search, and backtrack some more!"

bool Traverse(char* input){

    RewriteRuleGroup* activeGroup;
    if(!g->ruleGroups->Count) throw runtime_error("empty grammar");
    activeGroup = (RewriteRuleGroup*)g->ruleGroups->Items[0];
    if(verbosity > 0) printf(("\nAssuming start symbol " + activeGroup->nonTerminal + "\n").c_str());

    //create parse node list
    TList* nodes = new TList();
    try{
        //set up first node
        ParseNode* node = new ParseNode();
        nodes->Add(node);
        node->myGroup = activeGroup;
        node->terminal = false;
        node->currentRuleIndex = 0;
        node->str = activeGroup->nonTerminal;

        int currentNodeIndex = 0;
        int inputPtr = 0;
        bool match;

        while(1){

            //find the next unmarked node
            node = NULL;
            for(int i=0; i<nodes->Count; i++){
                ParseNode* newNode = (ParseNode*)nodes->Items[i];
                if(newNode->index == -1){ node = newNode; break; }
            }
            if(!node){
                //are we at the end of the string? [I hope?]
                if(input[inputPtr] == 0){

                    //there's still a small chance that the terminal trace of the nodes
                    //does not match output
                    if(!MatchNodeTrace(nodes, input)){
                        goto backtrack;
                    }

                    //we're done!!!
                    if(verbosity > 0) printf("Success!\n");
                    //show the parse tree
                    TfrmTree* theForm = new TfrmTree(NULL);
                    theForm->FillTree(nodes, (ParseNode*)nodes->Items[0], NULL);
                    theForm->TreeView1->FullExpand();
                    theForm->ShowModal();
                    delete theForm;
                    return true;

                }else{

                    //This condition occurs when the algorithm is "successful"
                    //all the way back to the start symbol, and yet there's still
                    //input remaining. This means only one thing:

                    //Backtrack!!!!!!
                    //My apologies, Father Dijkstra:
                    goto backtrack;

                }
            }

            if(!node->terminal){
                //if the node is a nonterminal, roll it out
                if(verbosity > 1) printflevel(node->level, ("Encountered nonterminal " + node->str + "\n").c_str());
                RewriteRule* currentRule = (RewriteRule*)node->myGroup->rules->Items[node->currentRuleIndex];

                if(verbosity > 1){ printflevel(node->level, ""); printNodes(nodes, node); }

                //this rule can only be used once. increment the rule used index
                node->currentRuleIndex++;

                if(verbosity > 0) printflevel(node->level, ("Rolling out nonterminal " + node->str + " -> ").c_str());

                //start inserting nodes directly after the current node index
                int insertPoint=currentNodeIndex+1;
                for(int i=0; i<currentRule->units->Count; i++){
                    RewriteUnit* unit = (RewriteUnit*)currentRule->units->Items[i];
                    ParseNode* newNode = new ParseNode();
                    newNode->index = -1;
                    newNode->parent = node;
                    newNode->level = node->level+1;
                    nodes->Insert(insertPoint++, newNode);
                    newNode->terminal = unit->terminal;
                    newNode->str = unit->str;
                    if(!newNode->terminal){
                        //find the group of this nonterminal
                        newNode->myGroup = g->getGroup(newNode->str);
                        newNode->currentRuleIndex = 0;
                    }
                    if(verbosity > 0){ if(newNode->str=="") printf("

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -