Nicolas Winkler 8 лет назад
Родитель
Сommit
dc2b74238c
4 измененных файлов с 108 добавлено и 30 удалено
  1. 56 9
      src/Parser.cpp
  2. 45 20
      src/Parser.h
  3. BIN
      src/a.out
  4. 7 1
      src/main.cpp

+ 56 - 9
src/Parser.cpp

@@ -1,7 +1,7 @@
 #include "Parser.h"
 #include <string>
 
-using zp::Parser;
+using namespace zp;
 using namespace std;
 
 Parser::Parser(istream& in) :
@@ -10,17 +10,64 @@ Parser::Parser(istream& in) :
 }
 
 
-void Parser::parse(void)
+unique_ptr<Block> Parser::parse(void)
 {
-    while (!in.eof())
-    {
-        char chr;
-        in >> chr;
+    return parseBlock(false);
+}
+
+
+unique_ptr<Block> Parser::parseBlock(bool isLoop)
+{
+    unique_ptr<UnionBlock> wrapper = nullptr;
+    unique_ptr<InstructionBlock> block = make_unique<InstructionBlock>();
+
+    char chr;
+    while (in >> chr) {
         switch(chr) {
             case '+':
-                program.instructions.push_back(
-                        std::make_unique<UnaryInstruction>());
+                block->addInstruction(Instruction::PLUS);
+                break;
+            case '-':
+                block->addInstruction(Instruction::MINUS);
+                break;
+            case '<':
+                block->addInstruction(Instruction::LEFT);
+                break;
+            case '>':
+                block->addInstruction(Instruction::RIGHT);
+                break;
+            case '.':
+                block->addInstruction(Instruction::DOT);
+                break;
+            case ',':
+                block->addInstruction(Instruction::COMMA);
+                break;
+            case '[':
+                if (wrapper == nullptr) {
+                    wrapper = isLoop ? make_unique<Loop>() : make_unique<UnionBlock>();
+                }
+                if (!block->isEmpty()) {
+                    wrapper->addBlock(move(block));
+                    block = make_unique<InstructionBlock>();
+                }
+                wrapper->addBlock(parseBlock(true));
+                break;
+            case ']':
+                if (isLoop) {
+                    if (wrapper == nullptr)
+                        return block;
+                    else
+                        return wrapper;
+                }
+                else
+                    throw ParserException("encountered unexpected ']'");
+            default:;
         }
     }
+    if (isLoop)
+        throw ParserException("number of '['s and ']'s not matching");
+    else if (wrapper == nullptr)
+        return block;
+    else
+        return wrapper;
 }
-

+ 45 - 20
src/Parser.h

@@ -4,55 +4,80 @@
 #include <iostream>
 #include <vector>
 #include <memory>
+#include <stdexcept>
 
 namespace zp
 {
-    struct Instruction;
-    struct UnaryInstruction;
+    enum class Instruction : char;
+
+    struct Block;
+    struct InstructionBlock;
+    struct UnionBlock;
     struct Loop;
 
     class Parser;
+    class ParserException;
 }
 
 
-struct zp::Instruction
+enum class zp::Instruction : char
 {
-    virtual ~Instruction(void) = default;
+    PLUS,
+    MINUS,
+    LEFT,
+    RIGHT,
+    DOT,
+    COMMA
 };
 
 
-struct zp::UnaryInstruction :
-    public Instruction
+struct zp::Block
 {
-    enum class Type : char
-    {
-        INC,
-        DEC,
-        LEFT,
-        RIGHT,
-        POINT,
-        COMMA
-    };
+    virtual ~Block(void) = default;
+};
+
+
+struct zp::InstructionBlock :
+    public Block
+{
+    std::vector<Instruction> instructions;
+
+    inline void addInstruction(Instruction i)               { instructions.push_back(i); }
+    inline bool isEmpty(void) const                         { return instructions.empty(); }
+};
 
-    Type type;
+
+struct zp::UnionBlock :
+    public Block
+{
+    std::vector<std::unique_ptr<Block>> instructions;
+    inline void addBlock(std::unique_ptr<Block>&& block)    { instructions.push_back(std::move(block)); }
 };
 
 
 struct zp::Loop :
-    public Instruction
+    public UnionBlock
 {
-    std::vector<std::unique_ptr<Instruction>> instructions;
 };
 
 
 class zp::Parser
 {
     std::istream& in;
-    Loop program;
 public:
     Parser(std::istream& in);
 
-    void parse(void);
+    std::unique_ptr<Block> parse(void);
+private:
+    std::unique_ptr<Block> parseBlock(bool);
+};
+
+
+class zp::ParserException :
+    public std::runtime_error
+{
+public:
+    inline ParserException(const std::string& what) : runtime_error(what) {}
 };
 
 #endif /* ZP_PARSER_H */


+ 7 - 1
src/main.cpp

@@ -30,7 +30,13 @@ int main(int argc, char** argv)
 
     Parser parser{*in};
 
-    parser.parse();
+    try {
+        unique_ptr<zp::Block> ast = parser.parse();
+    }
+    catch(zp::ParserException& pe) {
+        cerr << "Error: " << pe.what() << endl;
+        return 1;
+    }
 
     if (filename != "") {
         dynamic_cast<ifstream*> (in)->close();