diff interps/pbrain/pbrain.cc @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/pbrain/pbrain.cc	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,365 @@
+/*
+Interpreter for the pbrain programming language (procedural Brainf**k)
+Copyright(C) Paul M. Parks
+All Rights Reserved.
+
+v1.4.3
+2004/07/15 12:10
+
+paul@parkscomputing.com
+http://www.parkscomputing.com/
+
+The syntax is the same as traditional Brainf**k, with the following 
+symbols added:
+
+(
+Begin procedure
+
+)
+End procecure
+
+:
+Call procedure identified by the value at the current location
+
+   
+Procedures are identified by numeric ID:
+
++([-])
+
+Assuming the current location is zero, defines a procedure number 1 that 
+sets the current location to zero when called.
+
+++(<<[>>+<<-]>[>+<-]>)
+
+Assuming the current location is zero, defines a procedure number 2 that 
+accepts two parameters. It adds parameter 1 and parameter 2 and places 
+the result in the location that was current when the procedure was 
+called, zeroing out parameters 1 and 2 in the process.
+
++++([-]>++++++++++[<++++>-]<++++++++>[-]++:.)
+
+Assuming the current location is zero, defines a procedure 3 that prints 
+the ASCII equivalent of the numeral at the current location, between 0 
+and 9.
+
++++>+++++>++:
+
+Calls procedure 2, passing in parameters 3 and 5.
+
+All of the above examples may be combined into the program below. Note that 
+the procedures are numbered 1, 2, and 3 because the current location is 
+incremented prior to each procedure definition.
+
++([-])
++(-:<<[>>+<<-]>[>+<-]>)
++([-]>++++++++++[<++++>-]<++++++++>[-]++:.)
+>+++>+++++>++:
+>+++:
+
+An error condition is reported with a short diagnostic to stderr and an 
+error number returned from the executable. Errors reported by the 
+interpreter are as follows:
+
+1 - Out of memory
+2 - Unknown procedure
+3 - Memory address out of range
+4 - Cannot find matching ] for beginning [
+999 - Unknown exception
+
+*/
+
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <iterator>
+#include <map>
+#include <cstdlib>
+
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4571)
+#endif
+
+// Define the type contained in the memory array
+#ifndef PBRAIN_MEM_TYPE
+#define PBRAIN_MEM_TYPE int
+#endif
+
+// Define the character input/output type.
+#ifndef PBRAIN_CHARACTER_TYPE
+#define PBRAIN_CHARACTER_TYPE wchar_t
+#endif
+
+// Set the initial size of the memory array, if not defined externally.
+#ifndef PBRAIN_INIT_MEM_SIZE
+#define PBRAIN_INIT_MEM_SIZE 30000
+#endif
+
+// By default, use a dynamic array to store memory locations.
+#ifndef PBRAIN_STATIC_MEMORY
+typedef std::vector<PBRAIN_MEM_TYPE> Mem;
+Mem mem(PBRAIN_INIT_MEM_SIZE);
+Mem::size_type mp = 0;
+#else
+PBRAIN_MEM_TYPE mem[PBRAIN_INIT_MEM_SIZE];
+size_t mp = 0;
+#endif
+
+
+// Placeholder template class to be specialized below.
+template<typename Ch> struct io_types{};
+
+
+// Define appropriate I/O and stream iterator types for working with byte 
+// characters.
+template<> struct io_types<char>
+{
+    static std::istream& cin;
+    static std::ostream& cout;
+    typedef std::basic_ifstream<char, std::char_traits<char> > ifstream;
+    typedef std::istream_iterator<char,char> istream_iterator;
+};
+
+std::istream& io_types<char>::cin = std::cin;
+std::ostream& io_types<char>::cout = std::cout;
+
+
+// Define appropriate I/O and stream iterator types for working with wide 
+// characters.
+template<> struct io_types<wchar_t>
+{
+    static std::wistream& cin;
+    static std::wostream& cout;
+    typedef std::basic_ifstream<wchar_t, std::char_traits<wchar_t> > ifstream;
+    typedef std::istream_iterator<wchar_t,wchar_t> istream_iterator;
+};
+
+std::wistream& io_types<wchar_t>::cin = std::wcin;
+std::wostream& io_types<wchar_t>::cout = std::wcout;
+
+
+// Useful type that chooses the appropriate typedefs for the character width
+typedef io_types<PBRAIN_CHARACTER_TYPE> io;
+
+// Type for storing a string of instructions; used for procedures and loops
+typedef std::vector<PBRAIN_CHARACTER_TYPE> SourceBlock;
+
+// Type for storing procedures indexed by number
+typedef std::map<PBRAIN_MEM_TYPE, std::vector<PBRAIN_CHARACTER_TYPE> > Procedures;
+
+
+// Map of procedure IDs to procedures
+Procedures procedures;
+
+
+// Interpret a container of instructions
+template<typename It> void interpret(It ii, It eos)
+{
+    while (ii != eos)
+    {
+        switch (*ii)
+        {
+            case '+':
+                ++mem[mp];         
+                break;
+
+            case '-':
+                --mem[mp];
+                break;
+
+            case '>':
+                ++mp;
+
+#ifndef PBRAIN_STATIC_MEMORY
+                // If memory is kept in a dynamic array, the array will grow as 
+                // needed.
+                try
+                {
+                    if (mp == mem.size())
+                    {
+                        mem.resize(mem.size() * 2);
+                    }
+                }
+                catch (...)
+                {
+                    // Ostensibly an out-of-memory condition.
+                    throw 1;
+                }
+#else
+                // Static memory cannot grow, so throw when limit reached
+                if (mp == sizeof(mem) / sizeof(PBRAIN_MEM_TYPE))
+                {
+                    throw 1;
+                }
+#endif
+
+                break;
+
+            case '<':
+                --mp;
+
+                // Throw out-of-range error if cell location is decremented below 0
+                if (static_cast<int>(mp) < 0)
+                {
+                    throw 3;
+                }
+
+                break;
+
+            case '.':
+                io::cout.put(static_cast<PBRAIN_CHARACTER_TYPE>(mem[mp]));
+                break;
+
+            case ',':
+                mem[mp] = static_cast<PBRAIN_MEM_TYPE>(io::cin.get());
+                break;
+
+            case '[':
+                // Move to first instruction in the loop
+                ++ii;
+
+                {
+                    int nest = 0;
+                    It begin = ii;
+
+                    // Find the matching ]
+                    while (ii != eos)
+                    {
+                        if (*ii == '[')
+                        {
+                            ++nest;
+                        }
+                        else if (*ii == ']')
+                        {
+                            if (nest)
+                            {
+                                --nest;
+                            }
+                            else
+                            {
+                                break;
+                            }
+                        }
+
+                        ++ii;
+                    }
+
+                    // If no matching ] is found in source block, report error.
+                    if (ii == eos)
+                    {
+                        throw 4;
+                    }
+
+                    // At this point the iterator will point at the matching ] 
+                    // character, which is one instruction past the end of the range 
+                    // of instructions to be processed in a loop.
+                    loop(begin, ii);
+                }
+
+                break;
+
+            case '(':
+                ++ii;
+
+                {
+                    SourceBlock sourceBlock;
+
+                    while (ii != eos && *ii != ')')
+                    {
+                        sourceBlock.push_back(*ii);
+                        ++ii;
+                    }
+
+                    procedures.insert(std::make_pair(mem[mp], sourceBlock));
+                }
+
+                break;
+
+            case ':':
+            {
+                // Look up the source block that matches the value at the current 
+                // location. If found, execute it.
+                Procedures::iterator i = procedures.find(mem[mp]);
+
+                if (i != procedures.end())
+                {
+                    interpret(i->second.begin(), i->second.end());
+                }
+                else
+                {
+                    throw 2;
+                }
+            }
+            break;
+
+            default:
+                break;
+        }
+
+        ++ii;
+    }
+}
+
+
+template<typename It> void loop(It ii, It eos)
+{
+    // Interpret instructions until the value in the current memory location 
+    // is zero
+    while (mem[mp])
+    {
+        interpret(ii, eos);
+    }
+}
+
+
+template<typename C> void parse(C& c)
+{
+    io::istream_iterator ii(c);
+    io::istream_iterator eos;
+
+    SourceBlock sourceBlock;
+
+    // Copy instructions from the input stream to a source block.
+    while (ii != eos)
+    {
+        sourceBlock.push_back(*ii);
+        ++ii;
+    }
+
+    // Execute the instructions in the source block
+    interpret(sourceBlock.begin(), sourceBlock.end());
+}
+
+
+int main(int argc, char** argv)
+{
+    try
+    {
+        // Read from a file if a filename is provided as an argument.
+        if (argc > 1)
+        {
+            io::ifstream source(argv[1]);
+
+            if (source.is_open())
+            {
+                parse(source);
+            }
+        }
+        // Otherwise interpret code from stdin
+        else
+        {
+            parse(io::cin);
+        }
+    }
+    catch(int e)
+    {
+        std::cerr << "Error " << e << ", cell " << (unsigned int)(mp) << "\n";
+        exit(e);
+    }
+    catch(...)
+    {
+        std::cerr << "Error " << 999 << ", cell " << (unsigned int)(mp) << "\n";
+        exit(999);
+    }
+}