MacroCmd.cpp 3.44 KB
Newer Older
gsell's avatar
gsell committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
// ------------------------------------------------------------------------
// $RCSfile: MacroCmd.cpp,v $
// ------------------------------------------------------------------------
// $Revision: 1.1.1.1 $
// ------------------------------------------------------------------------
// Copyright: see Copyright.readme
// ------------------------------------------------------------------------
//
// Class: MacroCmd
//
// ------------------------------------------------------------------------
//
// $Date: 2000/03/27 09:33:43 $
// $Author: Andreas Adelmann $
//
// ------------------------------------------------------------------------

#include "OpalParser/MacroCmd.h"
#include "AbstractObjects/OpalData.h"
#include "OpalParser/OpalParser.h"
#include "Parser/Statement.h"
#include "Utilities/ParseError.h"
#include <vector>
#include <cassert>

// Class MacroCmd
// ------------------------------------------------------------------------

MacroCmd::MacroCmd():
    Macro(0u, "MACRO",
          "A \"MACRO\" command defines a subroutine:\n"
          "\t<name>(<arguments>):MACRO{<body>}"),
    body(0)
{}


37
MacroCmd::MacroCmd(const std::string &name, MacroCmd *parent):
gsell's avatar
gsell committed
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
    Macro(name, parent), body() {
    body = new MacroStream(name);
}


MacroCmd::~MacroCmd()
{}


void MacroCmd::execute() {
    body->start();
    itsParser->run(&*body);
}


Object *MacroCmd::makeInstance
54
(const std::string &name, Statement &statement, const Parser *parser) {
gsell's avatar
gsell committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    parseActuals(statement);

    // Check for consistency in argument number.
    if(formals.size() != actuals.size()) {
        throw ParseError("MacroCmd::makeInstance()",
                         "Inconsistent number of macro arguments.");
    }

    // Substitute the actual arguments.
    MacroCmd *macro = new MacroCmd(name, this);
    macro->itsParser = parser;
    body->start();
    Token token = body->readToken();

    while(! token.isEOF()) {
        bool found = false;

        if(token.isWord()) {
73
            std::string word = token.getWord();
gsell's avatar
gsell committed
74

75
            for(std::vector<std::string>::size_type i = 0;
gsell's avatar
gsell committed
76 77 78
                i < formals.size(); i++) {
                if(word == formals[i]) {
                    std::vector<Token> act = actuals[i];
79 80
                    for(Token t : act) {
                        macro->body->append(t);
gsell's avatar
gsell committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
                    }
                    found = true;
                    break;
                }
            }
        }

        if(! found) macro->body->append(token);
        token = body->readToken();
    }

    return macro;
}


Object *MacroCmd::makeTemplate
97
(const std::string &name, TokenStream &, Statement &statement) {
gsell's avatar
gsell committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    MacroCmd *macro = new MacroCmd(name, this);
    macro->parseFormals(statement);

    // Parse macro body->
    assert(statement.keyword("MACRO"));
    Token token;

    if(statement.delimiter('{')) {
        int level = 1;
        while(true) {
            if(statement.atEnd()) {
                throw ParseError("MacroCmd::makeTemplate()",
                                 "MACRO body is not closed.");
            } else {
                token = statement.getCurrent();

                if(token.isDel('{')) {
                    ++level;
                } else if(token.isDel('}')) {
                    if(--level == 0) break;
                }

                macro->body->append(token);
            }
        }
    } else {
        throw ParseError("MacroCmd::makeTemplate()",
                         "Missing MACRO body, should be \"{...}\".");
    }

    return macro;
}