[QUOTE=Eudoxia;17767045]I've been using Geany to compile this experimental interpreter, but DAMN it doesn't work:[/QUOTE]
Do you mean it doesn't compile, or doesn't work?
Because it compiles file with CodeBlocks, shows a little prompt and all
The commands, they don't respond ;_;
For example, if I type:
:q
It should terminate the program (Obvious label is obvious), but it doesn't respond.
[editline]05:18AM[/editline]
Shit...
The problem is in cin >> whatever.
I wanted to include as many arguments as possible, but the program requires you to enter ALL of them to perform an action..
Then just do cin >> var when you need it (e.g. when keyword == "out").
Also, there is no argument[4], only argument[0-3].
[QUOTE=jivemasta;17759298]I'd say for chars you just do the letter. Then for strings you do "string". " would be an operator that automatically adds all the chars to the memory until it gets to a second " and then it adds a 0 to the end. So, for example:
[code]
"Hello"
[/code]
Would work exactly the same as:
[code]
H>e>l>l>o>0
[/code]
But look less confusing. Then you could also have $ be a operator to print a string starting at a the current memory index until it gets to a 0 or null.[/QUOTE]
By prefixing chars I wanted to differentiate between the char 1 (which is 31 in ASCII) and the number 1.
Also, the current specs say, that the memory-index shall return to the first letter. I think it should stay where it is after insertion, so you can put more stuff behind the string.
[QUOTE=ZeekyHBomb;17771539]By prefixing chars I wanted to differentiate between the char 1 (which is 31 in ASCII) and the number 1.[/QUOTE]
There could be an operator too I guess, for that sort of thing, I wasn't thinking of that. Maybe do ' for a single char as in '1 or '+. Then "string" for strings like I said before. I still think the automatic 0 after a string input is a good idea so you can do $ to print a string. One problem that comes to mind is if you append to a string, you would overwrite the 0 and could cause huge errors and massive headaches, which goes against the easy brainfuck idea.
One should also differentiate between user input as chars and integers.
I'd say a single , is integer and ', would be asking for a char.
Maybe EBf just shouldn't have real strings (e.g. end with 0). That datatype is just too complex to be built in and safe for such a language, I guess.
EDIT: Maybe the programmer should just null-terminate the string him/herself. I mean, how many people are going to use this language anyways?
Also, what shall happen if you get something like that:
"@(a)" or "@()" or @ with incomplete or no parenthesis at all?
Same question with !.
And what happens if the specified cell is not available (e.g. @(55) or !(55), but there are only 10 cells)?
And shouldn't a \ be put into memory with "'\\", not "'\"?
(Using "EBf code" to not waste space by code-tags .. and because of lazyness to write them)
[QUOTE=ZeekyHBomb;17771539]Then just do cin >> var when you need it (e.g. when keyword == "out").
Also, there is no argument[4], only argument[0-3].
By prefixing chars I wanted to differentiate between the char 1 (which is 31 in ASCII) and the number 1.
Also, the current specs say, that the memory-index shall return to the first letter. I think it should stay where it is after insertion, so you can put more stuff behind the string.[/QUOTE]
Yeah, but to print, say, "hello", the user would have to type:
print
[press return]
hello
[press return]
I wanted to make the interpreter a command.line interpreter :saddowns:
Well, I'm guessing that will have to wait.
Or I could code that loop I designed, but no, it's too boring.
And.. err.. what do you want?
print hello [press return]? Then you could do
[cpp]std::string line;
std::cin >> line;
std::vector<std::string> > commands(std::count(line.begin(), line.end(), ' ')+1);
if(commands.size() == 1) { //only one command
commands[0] = line;
} else {
std::string::size_type pos1 = 0, pos2 = line.find_first_of(' ');
assert(pos2 != std::string::npos);
for(std::vector::size_t i = 0; i != commands.length(); ++i) {
commands[i] = line.substr(pos1, pos2);
pos1 = pos2;
pos2 = line.find_first_of(' ');
}
assert(pos1 != std::string::npos && pos2 == std::string::npos);
}[/cpp]
and each element in the vector will be one single command/argument.
[QUOTE=ZeekyHBomb;17775469]And.. err.. what do you want?
print hello [press return]? Then you could do
[cpp]std::string line;
std::cin >> line;
std::vector<std::string> > commands(std::count(line.begin(), line.end(), ' ')+1);
if(commands.size() == 1) { //only one command
commands[0] = line;
} else {
std::string::size_type pos1 = 0, pos2 = line.find_first_of(' ');
assert(pos2 != std::string::npos);
for(std::vector::size_t i = 0; i != commands.length(); ++i) {
commands[i] = line.substr(pos1, pos2);
pos1 = pos2;
pos2 = line.find_first_of(' ');
}
assert(pos1 != std::string::npos && pos2 == std::string::npos);
}[/cpp]
and each element in the vector will be one single command/argument.[/QUOTE]
Thanks, I'll see if I can implement that.
Alright, here's my crack at "EBF" parsing, it's not actually the same syntax since I haven't been keeping check on this thread, so I might just rename it. But here is the current syntax, along with the rest of the help file.
[cpp]
NAME: easybf - Easy Brainfuck Interpreter
SYNOPSIS: easybf [OPTION]... [FILE]...
DESCRIPTION
-d
Debug mode, verbose, outputs all important debug information
-h
Help, displays this message
--length=######
Sets the maximum size of the memory to work on
SYNTAX
>
Increase index position by 1
<
Decrease index position by 1
0-9
Assigns the number to current memory
a-zA-Z
Assigns the integer value of the letter (or space) to current memory
'##'
Assigns ## (Any length number) to current memory
+-/*
Perform operation on current memory and next memory value
@
Copy current memory to next position
#
Copy current memory to previous position
.
Print current memory contents as integer
:
Print current memory contents as character
,
Get single character input and store it in current memory
|
Get one number input (any length) and store in current memory
!
Set index location to current memory value
{}
Loop contents until current memory = 0
[]
Skip contents if current memory = 0
$
Store current memory
~*~
Anything between two ~'s is ignored completely
%
Copy stored memory to current memory
NOTES
Spaces are considered a valid input, so the program "1 >" would set the first memory
block to the number 10 (ASCII for space).
AUTHOR
Written by Jake Woods
REPORTING BUGS
Report bugs to <vodurden@gmail.com>
[/cpp]
(cpp tags used to preserve indention)
Notes:
Currently it only works under linux, the code is 100% portable (as far as I am aware) but I haven't compiled a windows version yet nor have I included cross-compilation into my makefile.
The current version was created using vim, make and g++ (4.3.3)
[b]Edit:[/b]
Slight mistake in the documentation, the ASCII code for space is not 10, it's 32.
10 is a new line.
Examples:
[cpp]H>e>l>o> >W>r>d>0!:>:>::>:>:>:<<:>>>:<<<<:>>>>>:[/cpp]
Output: Hello World
[cpp]E>n>t>e>r> >a>i>m>'10'>0!
:>:>:>:>:>:~Enter~
>:<:>~a~
<<<<:>>>>>:>:<<<<<:>>>>>>:>:~time\n~
|>1<{.-<:>}~Counts down~[/cpp]
Output:
Enter a Time
[User Number here]
[Countdown from $USERNUMBER to 0]
Here's the release link, enjoy and let me know about the bugs you will inevitably find.
[url]http://www.electronicfiles.net/files/11823/easybf.rar[/url]
For those who don't want to download the entire release, here's the code:
[b]main.cpp[/b]
[cpp]
#include <iostream>
#include <map>
#include <cstring>
#include <sstream>
#include <vector>
#include "FlagMachine.h"
#include "EasyBrainfuckMachine.h"
#include "tools.h"
int main(int argc, char** argv)
{
FlagMachine flags("dlh", argc, argv);
bool debug = (flags.getFlag('d') == FlagMachine::FLAG_TRUE) ? true : false;
unsigned int length = (flags.getFlag('l') == FlagMachine::FLAG_FALSE) ? 200 : from_string<int>(flags.getFlag('l').c_str());
if(flags.getFlag('h') == FlagMachine::FLAG_TRUE)
{
std::cout << "NAME: easybf - Easy Brainfuck Interpreter" << std::endl <<
"SYNOPSIS: easybf [OPTION]... [FILE]..." << std::endl << std::endl <<
"DESCRIPTION" << std::endl <<
"\t-d\n\t\tDebug mode, verbose, outputs all important debug information" << std::endl <<
"\t-h\n\t\tHelp, displays this message" << std::endl <<
"\t--length=######\n\t\tSets the maximum size of the memory to work on" << std::endl << std::endl <<
"SYNTAX" << std::endl <<
"\t>\n\t\tIncrease index position by 1" << std::endl <<
"\t<\n\t\tDecrease index position by 1" << std::endl <<
"\t0-9\n\t\tAssigns the number to current memory" << std::endl <<
"\ta-zA-Z \n\t\tAssigns the integer value of the letter (or space) to current memory" << std::endl <<
"\t\'##\'\n\t\tAssigns ## (Any length number) to current memory" << std::endl <<
"\t+-/*\n\t\tPerform operation on current memory and next memory value" << std::endl <<
"\t@\n\t\tCopy current memory to next position" << std::endl <<
"\t#\n\t\tCopy current memory to previous position" << std::endl <<
"\t.\n\t\tPrint current memory contents as integer" << std::endl <<
"\t:\n\t\tPrint current memory contents as character" << std::endl <<
"\t,\n\t\tGet single character input and store it in current memory" << std::endl <<
"\t|\n\t\tGet one number input (any length) and store in current memory" << std::endl <<
"\t!\n\t\tSet index location to current memory value" << std::endl <<
"\t{}\n\t\tLoop contents until current memory = 0" << std::endl <<
"\t[]\n\t\tSkip contents if current memory = 0" << std::endl <<
"\t$\n\t\tStore current memory" << std::endl <<
"\t~*~\n\t\tAnything between two ~'s is ignored completely" << std::endl <<
"\t%\n\t\tCopy stored memory to current memory" << std::endl << std::endl <<
"NOTES" << std::endl <<
"\tSpaces are considered a valid input, so the program \"1 >\" would set the first memory\n\tblock to the number 10 (ASCII for space)." << std::endl << std::endl <<
"AUTHOR" << std::endl <<
"\tWritten by Jake Woods" << std::endl << std::endl <<
"REPORTING BUGS" << std::endl <<
"\tReport bugs to <vodurden@gmail.com>" << std::endl;
return 0;
}
std::vector<std::string> programs;
for(int arg = 1; arg < argc; ++arg)
{
if (argv[arg][0] != '-')
{
std::string program = argv[arg];
programs.push_back(program);
}
}
EasyBrainfuckMachine interpreter(debug, length);
for(std::vector<std::string>::iterator mIter = programs.begin(); mIter != programs.end(); ++mIter)
{
interpreter.execute((*mIter));
}
if(programs.size() == 0)
{
std::cout << "No input files specified" << std::endl;
}
}
[/cpp]
[b]EasyBrainfuckMachine.h[/b]
[cpp]
#ifndef EASYBRAINFUCKMACHINE_H_INCLUDED
#define EASYBRAINFUCKMACHINE_H_INCLUDED
#include <fstream>
#include <string>
#include <vector>
#include <iostream>
#include "tools.h"
class EasyBrainfuckMachine
{
private:
bool m_debug;
unsigned int m_indexPointer;
unsigned int m_storage;
std::string m_program;
std::vector<unsigned int> m_dataspace;
void debugMessage(const std::string& message);
void parseLoop(const std::string& loop, std::string::iterator &commandIter);
void parseCommand(const char command, std::string::iterator &commandIter);
void loadProgram(const std::string& filepath);
public:
EasyBrainfuckMachine(bool debug=false, int length=200);
void execute(const std::string& filepath);
void printMemory(const int begin=0, const int end=20);
};
#endif
[/cpp]
[b]EasyBrainfuckMachine.cpp[/b]
[cpp]
#include "EasyBrainfuckMachine.h"
EasyBrainfuckMachine::EasyBrainfuckMachine(bool debug, int length) :
m_debug(debug), m_dataspace(length), m_indexPointer(0)
{
}
void EasyBrainfuckMachine::loadProgram(const std::string& filepath)
{
m_indexPointer = 0;
m_program = "";
std::ifstream file(filepath.c_str());
if (!file)
{
std::cerr << "Unable to open file " << filepath << std::endl;
}
else
{
std::string command;
while(std::getline(file,command))
{
m_program += command;
}
for(std::vector<unsigned int>::iterator memory = m_dataspace.begin(); memory != m_dataspace.end(); ++memory)
{
(*memory) = 0;
}
}
}
void EasyBrainfuckMachine::execute(const std::string& filepath)
{
loadProgram(filepath);
for(std::string::iterator commandIter = m_program.begin(); commandIter != m_program.end(); ++commandIter)
{
char command = (*commandIter);
parseCommand(command, commandIter);
}
std::cout << std::endl;
}
void EasyBrainfuckMachine::debugMessage(const std::string& message)
{
if(m_debug)
{
std::cout << message << std::endl;
int section = m_indexPointer / 4;
printMemory(section*4, (section*4)+4);
}
}
void EasyBrainfuckMachine::printMemory(const int begin, const int end)
{
int pos = begin;
std::string numberline = "";
std::string memoryline = "";
for(std::vector<unsigned int>::iterator memory = m_dataspace.begin() + begin; memory != m_dataspace.begin() + (end+1); ++memory)
{
std::string decoration = " ";
std::string curnumber = to_string<int>(*memory);
if(pos == m_indexPointer)
{
decoration = " >";
}
std::cout << decoration << pos << ": " << curnumber << std::endl;
pos = pos + 1;
}
}
void EasyBrainfuckMachine::parseCommand(const char command, std::string::iterator& commandIter)
{
if(command == '<')
{
m_indexPointer -= 1;
debugMessage("Decreased Index");
}
else if(command == '>')
{
m_indexPointer += 1;
debugMessage("Increased Index");
}
else if(command == ':')
{
debugMessage("Printing Character");
std::cout << char(m_dataspace[m_indexPointer]);
}
else if(command == '.')
{
debugMessage("Printing Number");
std::cout << int(m_dataspace[m_indexPointer]);
}
else if(command == '+')
{
m_dataspace[m_indexPointer] += m_dataspace[m_indexPointer+1];
debugMessage("Memory Addition");
}
else if(command == '-')
{
m_dataspace[m_indexPointer] -= m_dataspace[m_indexPointer+1];
debugMessage("Memory Subtraction");
}
else if(command == '/') //Rounds up to nearest whole number
{
float result = float(m_dataspace[m_indexPointer]) / float(m_dataspace[m_indexPointer+1]);
m_dataspace[m_indexPointer] = static_cast<int>(result + (result > 0.0 ? 0.5 : -0.5));
debugMessage("Memory Division");
}
else if(command == '$')
{
m_storage = m_dataspace[m_indexPointer];
debugMessage("Stored Memory");
}
else if(command =='%')
{
m_dataspace[m_indexPointer] = m_storage;
debugMessage("Copied to memory from storage");
}
else if(command == '{')
{
debugMessage("Entering Loop");
std::string loopstr = "";
loopstr += command;
do
{
commandIter++;
loopstr += (*commandIter);
}
while((*commandIter) != '}');
parseLoop(loopstr, commandIter);
}
else if(command == '\'')
{
char curCommand;
std::string input = "";
do
{
commandIter++;
curCommand = (*commandIter);
if(is_number(curCommand))
{
input += curCommand;
}
else if(curCommand != '\'')
{
std::cout << "Error invalid number: " << curCommand << " found in number sequence: " << input << std::endl;
}
}
while ( curCommand != '\'' );
m_dataspace[m_indexPointer] = from_string<int>(input);
debugMessage("Set Memory (Number String)");
}
else if(command == '[')
{
if ( m_dataspace[m_indexPointer] == 0 )
{
char curCommand;
int leftBracketCount = 1;
do
{
commandIter++;
curCommand = (*commandIter);
if(curCommand == ']')
{
leftBracketCount -= 1;
}
else if(curCommand == '[')
{
leftBracketCount += 1;
}
}
while(leftBracketCount > 0);
debugMessage("Skipping Block");
}
}
else if(command == '~')
{
char curCommand;
do
{
commandIter++;
curCommand = (*commandIter);
}
while (curCommand != '~');
}
else if(command == '*')
{
m_dataspace[m_indexPointer] *= m_dataspace[m_indexPointer+1];
debugMessage("Memory Multiplication");
}
else if(command == '!')
{
m_indexPointer = m_dataspace[m_indexPointer];
debugMessage("Index Jump");
}
else if(command == ',')
{
char data;
std::cin >> data;
if(is_number(data))
{
m_dataspace[m_indexPointer] = (int(data) - int('0'));
}
else
{
m_dataspace[m_indexPointer] = int(data);
}
debugMessage("Input Value");
}
else if(command == '|')
{
int data;
std::cin >> data;
m_dataspace[m_indexPointer] = data;
}
else if(command == '#')
{
m_dataspace[m_indexPointer-1] = m_dataspace[m_indexPointer];
debugMessage("Copied value backwards");
}
else if(command == '@')
{
m_dataspace[m_indexPointer+1] = m_dataspace[m_indexPointer];
debugMessage("Copied value forwards");
}
else if(is_valid_input(command))
{
if(is_number(command))
{
m_dataspace[m_indexPointer] = int(command) - int('0');
}
else
{
m_dataspace[m_indexPointer] = int(command);
}
debugMessage("Set Memory");
}
}
void EasyBrainfuckMachine::parseLoop(const std::string& loop, std::string::iterator &commandIter)
{
std::string loopstr = loop;
loopstr.erase(0, 1);
size_t len = loopstr.length();
loopstr.erase(len-1, len);
int stringIndex = 0;
bool looping = true;
while(looping)
{
parseCommand(loopstr[stringIndex], commandIter);
stringIndex += 1;
if(stringIndex > len)
{
if(m_dataspace[m_indexPointer] == 0)
{
looping = false;
}
stringIndex = 0;
}
}
debugMessage("Exiting Loop");
}
[/cpp]
[b]FlagMachine.h[/b]
[cpp]
#ifndef FLAGMACHINE_H_INCLUDED
#define FLAGMACHINE_H_INCLUDED
#include <map>
#include <string>
#include <cstring>
#include <iostream>
class FlagMachine
{
private:
std::string m_validflags;
std::map<const char, std::string> m_flags;
public:
static const std::string FLAG_TRUE;
static const std::string FLAG_FALSE;
FlagMachine(const std::string& validflags, int argc, char** argv);
~FlagMachine();
void addValidFlags(const std::string& validflags);
void parseFlagString(int argc, char** argv);
void setFlag(const char flag, const std::string& data = FLAG_TRUE);
void printFlags();
const std::string& getFlag(const char);
};
#endif
[/cpp]
[b]FlagMachine.cpp[/b]
[cpp]
#include "FlagMachine.h"
const std::string FlagMachine::FLAG_TRUE = "1";
const std::string FlagMachine::FLAG_FALSE = "0";
FlagMachine::FlagMachine(const std::string& validflags, int argc, char** argv) :
m_validflags(validflags)
{
addValidFlags(validflags);
parseFlagString(argc, argv);
}
FlagMachine::~FlagMachine()
{
}
void FlagMachine::addValidFlags(const std::string& validflags)
{
for(std::string::iterator mIter = m_validflags.begin(); mIter != m_validflags.end(); ++mIter)
{
m_flags[(*mIter)] = FLAG_FALSE;
}
}
void FlagMachine::parseFlagString(int argc, char** argv)
{
for(int arg = 1; arg < argc; ++arg)
{
if ( strlen( argv[arg] ) > 2 && (argv[arg][0] == '-' && argv[arg][1] == '-'))
{
std::string flagString(argv[arg]);
flagString.erase(0, 2);
size_t split = flagString.find('=');
std::string lhs = flagString.substr(0, split);
std::string rhs = flagString.substr(split+1, flagString.length());
setFlag(lhs[0], rhs);
}
else if(argv[arg][0] == '-')
{
std::string flagString(argv[arg]);
flagString.erase(0, 1);
for(std::string::iterator flag = flagString.begin(); flag != flagString.end(); ++ flag)
{
setFlag((*flag));
}
}
}
}
void FlagMachine::setFlag(const char flag, const std::string& data)
{
if(m_flags.find(flag) != m_flags.end())
{
m_flags[flag] = data;
}
else
{
std::cout << "Invalid flag: " << flag << ", ignoring" << std::endl;
}
}
void FlagMachine::printFlags()
{
for (std::map<const char, std::string>::iterator mIter = m_flags.begin(); mIter != m_flags.end(); ++mIter)
{
std::cout << mIter->first << ": " << mIter->second << std::endl;
}
}
const std::string& FlagMachine::getFlag(const char flag)
{
return m_flags[flag];
}
[/cpp]
[b]tools.h[/b]
[cpp]
#ifndef TOOLS_H_INCLUDED
#define TOOLS_H_INCLUDED
#include <string>
#include <sstream>
template <class T>
T from_string(const std::string& s)
{
std::string str(s);
std::istringstream stream(str);
T type;
stream >> type;
return type;
}
template <class T>
std::string to_string(const T& v)
{
std::ostringstream stream;
stream << v;
std::string str = stream.str();
return str;
}
bool is_number(const char number);
bool is_number(const std::string& number);
bool is_valid_input(const char character);
#endif
[/cpp]
[b]tools.cpp[/b]
[cpp]
#include "tools.h"
bool is_number(const char number)
{
return(int(number) >= 48 && int(number <= 57));
}
bool is_number(const std::string& number)
{
return 1;
}
bool is_valid_input(const char character)
{
if(int(character) >= 48 && int(character<= 57))
{
return true;
}
else if(int(character) >= 65 && int(character) <= 90)
{
return true;
}
else if(int(character) >= 97 && int(character) <= 122)
{
return true;
}
else if(int(character) == 32)
{
return true;
}
return false;
}
[/cpp]
Sorry, you need to Log In to post a reply to this thread.