OrderClose function not working correctly - mql4

Is this the correct implementation of OrderClose()?
for(int ii = 0; ii < OrdersTotal(); ii++)
{
if(OrderSelect(ii, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType() == OP_BUY && OrderMagicNumber() == MagicStart && OrderSymbol() == symb)
{
int tikt = OrderTicket();
if(!OrderClose(tikt,OrderLots(),bid,4,clrPurple))
{
Print("Close Error", GetLastError());
}
}
if(OrderType() == OP_SELL && OrderMagicNumber() == MagicStart && OrderSymbol() == symb)
{
int tikt = OrderTicket();
if(!OrderClose(tikt,OrderLots(),ask,4,clrPurple))
{
Print("Close Error", GetLastError());
}
}
}
}
I am using this code right before opening a trade. For example, if there is a signal to buy then it closes the sell first and then opens a buy, and if there is a sell signal then it closes a sell first and then opens a buy.
But it only does this for the first time and wont work after that. Let's say there is a sell signal. Then it will close the buy and open the sell, but when there is a second signal for a buy then it won't close the sell neither will it open a buy.
There is no error in the experts tab. The only thing I receive in the experts tab is a message like this: Positions order mismatch. It does not appear like an error or a warning, it just appears as a message.

If you want to close all orders, you need to start iteration from the latest order position to the first position.
Try this:
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS))
{
if(OrderType() == OP_BUY)
{
if(!OrderClose(OrderTicket(), OrderLots(), Bid, 0))
{
Print("Error closing order: ", GetLastError());
}
}
if(OrderType() == OP_SELL)
{
if(!OrderClose(OrderTicket(), OrderLots(), Ask, 0))
{
Print("Error closing order: ", GetLastError());
}
}
}
}
You shouldn't start iterating from 0 when you are closing orders, because OrdersTotal() function decrement its value while you loop through all orders and closing them one by one.
For example (in your loop) you have 5 orders:
i = 0, OrdersTotal() = 5 -> close order on position 0.
i = 1, OrdersTotal() = 4 -> close order on position 1.
i = 2, OrdersTotal() = 3 -> close order on position 2.
i = 3, and now loop is over, because i == OrdersTotal().
Additionally, instead of int tikt= OrderTicket();, just use OrderTicket() in OrderClose() function.

Try the following code which is more robust and does not assume the orders to be closed are of the same symbol of the chart the EA is running on. This will close all orders on the account. If you want to restrict this to orders that are on the chart the EA is running on, or orders only opened by the EA, you should use OrderSymbol() and OrderMagicNumber() to filter the orders before closing them.
if(OrdersTotal()>0)
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderType()==OP_BUY || OrderType()==OP_SELL)
{
double price;
if(OrderType()==OP_BUY) price=MarketInfo(OrderSymbol(),MODE_BID); else price=MarketInfo(OrderSymbol(),MODE_ASK);
int ticket=OrderTicket();
bool res=OrderClose(ticket, OrderLots(), price, 50, clrNONE);
if(!res) Print("Error Closing Ticket #", IntegerToString(ticket));
}
else
{
int ticket=OrderTicket();
bool res=OrderDelete(ticket);
if(!res) Print("Error Closing Ticket #", IntegerToString(ticket));
}
}
}
}

Related

My do while loop is not entering the while loop

I'm trying to complete my homework assignment and am having trouble. The instructions state that I need to change the while expression to a not but whenever I do it wont enter the loop.
import java.util.Scanner;
public class GuessNumberApp {
public static void main(String[] args) {
final int LIMIT = 10;
System.out.println("Guess the number!");
System.out.println("I'm thinking of a number from 1 to " + LIMIT);
System.out.println();
// get a random number between 1 and the limit
double d = Math.random() * LIMIT; // d is >= 0.0 and < limit
int number = (int) d; // convert double to int
number++; // int is >= 1 and <= limit
Scanner sc = new Scanner(System.in);
int count = 1;
int guess;
do {
System.out.print("Your guess: ");
guess = Integer.parseInt(sc.nextLine());
}
while (guess != number); {
if (guess < 1 || guess > LIMIT) {
System.out.println("Invalid guess. Try again.");
}
else if (guess < number) {
System.out.println("Too low.");
count++;
}
else if (guess > number) {
System.out.println("Too high.");
count++;
}
}
System.out.println("You guessed it in " + count + " tries.\n");
System.out.println("Bye!");
}
}

How to calculate indicator buffer only once per day mql4

I have an indicator which gives one signal [Down Buffer]... I wish to only give signal once per day... Like after the first signal it will not paint any signal for the rest of the day! I have tested with below code it's now not painting at all?
//--- indicator buffers
double Buffer1[];
int day = 0;
int OnInit()
{
........................
}
int OnCalculate(......)
{
//--- main loop
for(int i = limit-1; i >= 0; i--)
{
//Indicator Buffer 1
if( here goes my condition )
{
if( day != Day() )
{
Buffer1[i] = High[i] + iATR(NULL, PERIOD_CURRENT, 14, i); //Set indicator value at Candlestick High + Average True Range
day = Day();
}
}
else
{
Buffer1[i] = EMPTY_VALUE;
}
}
return(rates_total);
}
What is wrong with my code? It's now not showing any signal at all...
Note : I have removed some of the code to make it simple...
Use the following function to check whether it is a new day.
It returns true if it is a new day, else returns false.
bool IsNewDay(){
static datetime prevDay = -1;
if( iTime(_Symbol, PERIOD_D1, 0) == prevDay ) return false;
prevDay = iTime(_Symbol, PERIOD_D1, 0);
return true;
}

Modify Pending Order at Mql4

I am trying to figure out an EA which updates its pending orders if current price pass the SL level of pending order both for buy and sell orders. As you can see below pic current price is below the SL point of pending orders. Therefore I want to modify new updated pending orders with openning price of from those SL point (+30 & -30 point) and not only for window currency but also for other currencies which are in the pending order list.
I tried below code but it didn't work out. Could you help me?
//------------------------------------------------------------------------------- 1 --
int start()
{
string Symb=Symbol(); // Symbol
//------------------------------------------------------------------------------- 2 --
for(int i=1; i<=OrdersTotal(); i++)
{
if (OrderSelect(i-1,SELECT_BY_POS)==true)
{
//---------------------------------------------------------------------- 3 --
if (OrderSymbol()== Symb) continue;
if (OrderType()==OP_BUYSTOP || OrderType()==OP_SELLSTOP) continue; // Market order
//---------------------------------------------------------------------- 4 --
{
int Tip =OrderType();
int Ticket=OrderTicket();
double Price =OrderOpenPrice();
double SL =OrderStopLoss();
double TP =OrderTakeProfit();
}
}
}
//------------------------------------------------------------------------------- 5 --
if (Tip==0)
{
Alert("For ",Symb," no pending orders available");
return;
}
//------------------------------------------------------------------------------- 6 --
while(true)
{
RefreshRates(); // Update data
//------------------------------------------------------------------------- 7 --
double c_bid =MarketInfo(Symb,MODE_BID); // Request for the value of Bid
double c_ask =MarketInfo(Symb,MODE_ASK); // Request for the value of Ask
//------------------------------------------------------------------------- 8 --
string Text=""; // Not to be modified
double New_SL=0;
double New_TP=0;
switch(Tip) // By order type
{
case 4: // BuyStopt
if (NormalizeDouble(SL,Digits) > // If it is further than by
NormalizeDouble(c_ask,Digits))//..the preset value
{
double New_Price=SL+30*Point; // Its new price
if (NormalizeDouble(SL,Digits)>0)
New_SL=New_Price-(Price-SL); // New StopLoss
if (NormalizeDouble(TP,Digits)>0)
New_TP=New_Price+(TP-Price); // New TakeProfit
Text= "BuyStopt "; // Modify it.
}
break; // Exit 'switch'
case 5: // SellStop
if (NormalizeDouble(SL,Digits) < // If it is further than by
NormalizeDouble(c_bid,Digits))//..the preset value
{
New_Price=SL-30*Point; // Its new price
if (NormalizeDouble(SL,Digits)>0)
New_SL=New_Price+(SL-Price); // New StopLoss
if (NormalizeDouble(TP,Digits)>0)
New_TP=New_Price-(Price-TP); // New TakeProfit
Text= "SellStop "; // Modify it.
}
}
if (NormalizeDouble(New_SL,Digits)<0) // Checking SL
New_SL=0;
if (NormalizeDouble(New_TP,Digits)<0) // Checking TP
New_TP=0;
if (Text=="") // If it is not modified
{
Alert("No conditions for modification.");
break; // Exit 'while'
}
//------------------------------------------------------------------------ 10 --
Alert ("Modification ",Text,Ticket,". Awaiting response..");
bool Ans=OrderModify(Ticket,New_Price,New_SL,New_TP,0);//Modify it!
//------------------------------------------------------------------------ 11 --
if (Ans==true) // Got it! :)
{
Alert ("Modified order ",Text," ",Ticket," :)");
break; // Exit the closing cycle
}
//------------------------------------------------------------------------ 12 --
int Error=GetLastError(); // Failed :(
switch(Error) // Overcomable errors
{
case 4: Alert("Trade server is busy. Retrying..");
Sleep(3000); // Simple solution
continue; // At the next iteration
case 137:Alert("Broker is busy. Retrying..");
Sleep(3000); // Simple solution
continue; // At the next iteration
case 146:Alert("Trading subsystem is busy. Retrying..");
Sleep(500); // Simple solution
continue; // At the next iteration
}
switch(Error) // Critical errors
{
case 2 : Alert("Common error.");
break; // Exit 'switch'
case 64: Alert("Account is blocked.");
break; // Exit 'switch'
case 133:Alert("Trading is prohibited");
break; // Exit 'switch'
case 139:Alert("Order is blocked and is being processed");
break; // Exit 'switch'
case 145:Alert("Modification prohibited. ",
"Order is too close to the market");
break; // Exit 'switch'
default: Alert("Occurred error ",Error);//Other alternatives
}
break; // Exit the closing cycle
} // End of closing cycle
//------------------------------------------------------------------------------ 13 --
Alert ("The script has completed its operations -----------------------");
return; // Exit start()
}
//------------------------------------------------------------------------------ 14 --
Welcome to the Worlds of MQL-4.56789...
Since the early days of the MQL4 language, the specifications 've changed a lot.
Your script suffers from a "recent"-New-MQL4.56789... change, where scope of validity of declared variables got restricted to a syntax-constructor-only ( this was not in the MQL4 original ).
So, declaring an int Tip et al but inside an if(){...}-block causes no Tip-variable to remain visible outside the {...}-block-constructor, not being know there anymore.
Next, your code requires a complete re-design, so as to meet your requirement of :
"not only for window currency but also for other currencies which are in the pending order list."
// ------------------------------------------------------------------------------- 2 --
for( int i=1; i <= OrdersTotal(); i++ )
{
if ( True == OrderSelect( i-1, SELECT_BY_POS ) )
{
//---------------------------------------------------------------------- 3 --
if ( OrderSymbol() == Symb ) continue; // ------------------------^ JIT/LOOP
if ( OrderType() == OP_BUYSTOP
|| OrderType() == OP_SELLSTOP
) continue; //-----------------------------------------------^ JIT/LOOP
// btw. was a pending { BUYSTOP || SELLSTOP }
//---------------------------------------------------------------------- 4 --
{ // a rest goes here :
int Tip = OrderType();
int Ticket = OrderTicket();
double Price = OrderOpenPrice();
double SL = OrderStopLoss();
double TP = OrderTakeProfit();
}
// ------------------------------ BUT ALL THESE GOT FORGOTTEN RIGHT HERE...
}
}
// ------------------------------------ OK, 've LOOPED THE WHOLE DB-POOL,
// BUT DID NOTHING SO FAR
// AND NOTHING SO FORTH
So, something evolved from this will help to settle the script on the rock-solid grounds :
#define MASK "(for i==(%3d)) got OrderTKT(%20d) of TYPE{BUY|SELL|BUYLIMIT|SELLLIMIT|BUYSTOP|SELLSTOP}=[%d] in (%10s)-MARKET ... WILL LOOP for a NEXT(?) ONE"
while ( !IsStopped() ) // ----------------------------------------------------------- 1 --
{ // (almost) INFINITE SCRIPT SERVICE LOOP
// as (almost) HEADLESS Sir NICHOLAS :)
string TradeSYMBOL;
int Tip;
int Ticket;
double Price;
double SL;
double TP;
if ( 1 > OrdersTotal() ) { Sleep( 333 ); continue; } // NOP / NAP ----------^ NOP/LOOP
// ------------------------------------------------------------------------------ 2 --
for( int i=0; i < OrdersTotal(); i++ ) // DB-POOL LOOP
{
if ( OrderSelect( i, SELECT_BY_POS ) )
{
//---------------------------------------------------------------------- 3 --
if ( OrderType() != OP_BUYSTOP
&& OrderType() != OP_SELLSTOP
) {
PrintFormat( MASK, i, OrderTicket(), OrderType(), OrderSymbol() );
continue; //-------------------------------------------------^ JIT/LOOP
} // btw. ! a pending { BUYSTOP || SELLSTOP }
//---------------------------------------------------------------------- 4 --
else
{ // a { BUYSTOP || SELLSTOP } go here :
// -------------------------------------------------------------------- SET :
Tip = OrderType();
Ticket = OrderTicket();
Price = OrderOpenPrice();
SL = OrderStopLoss();
TP = OrderTakeProfit();
TradeSYMBOL = OrderSymbol();
// ------------------------------------------------------------- PROCESS it :
RefreshRates();
...
// Alert() - a blocking GUI operation, quite dangerous in auto-trading
// any
// OrderModify() - has also to respect the Broker-defined {Stop|Freeze}Level
...
} // { BUYSTOP || SELLSTOP }
} // .SELECT
} // .DB-POOL LOOP________________________________________________________
} // .SERVICE LOOP........................................................

How to make Break even trigger more than one time in one entry

I now trying to make Break Even Code trigger more than one time,
example EA entry is 1.28000 and stop loss 1.28500
if current price reach 1.175000(50pips), sl move to break even such as to 1.28000(5pips).
EA will not make more modify order after condition are meet.
so how to trigger break even again if price reach 1.17000(100pips), sl move to (1.175000)(50 pips)
and again price reach 1.165000(150pips),sl move to 1.17000(100pips)
I want to make
BE_B_M(sl move to(example:5))
and
BE_B_T(price reach(example:50))
as variable and every time price reach target variable change to next value
so became
BE_B_M(sl move to(example:50)) and BE_B_T(price reach(example:100))
The entire code is as follows
extern double BE_T_1 = 50;
extern double BE_M_1 = 5;
extern double BE_T_2 = 100;
extern double BE_M_2 = 50;
extern double BE_T_3 = 150;
extern double BE_M_3 = 100;
double BE_S_M;
double BE_S_T;
void MOVE_BE_1()
{
for(int b=OrdersTotal()-1;b>=0;b--)
{
if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
if(OrderMagicNumber()!=M_Number)continue;
if(OrderSymbol()==Symbol())
if(OrderType()==OP_BUY)
if(Bid-OrderOpenPrice()>BE_S_T*Pips)
if(OrderOpenPrice()>OrderStopLoss())
if(!OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+(BE_S_M*Pips),OrderTakeProfit(),0,CLR_NONE))
Print("eror");
}
for(int s=OrdersTotal()-1;s>=0;s--)
{
if(OrderSelect(s,SELECT_BY_POS,MODE_TRADES))
if(OrderMagicNumber()!=M_Number)continue;
if(OrderSymbol()==Symbol())
if(OrderType()==OP_SELL)
if(OrderOpenPrice()-Ask>BE_S_T*Pips)
if(OrderOpenPrice()<OrderStopLoss())
if(!OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-(BE_S_M*Pips),OrderTakeProfit(),0,CLR_NONE))
Print("eror");
}
}
i expect sl will move after price reach every 50pips from entry
Here you can put all the 3 break even levels on one function.
Note: you can use 1 for-loop for both OP_BUY and OP_SELL
Here is my OnInit()
// Global variable
double point;
int OnInit()
{
if(Digits == 5 || Digits == 3) point=Point*10;
else point=Point;
return(INIT_SUCCEEDED);
}
Here is the BreakEven() function
//+------------------------------------------------------------------+
//| Break even the trade at 3 levels |
//+------------------------------------------------------------------+
void BreakEven()
{
// get the stop level for that symbol
double stopLevel = SymbolInfoInteger(Symbol(),SYMBOL_TRADE_STOPS_LEVEL)*Point;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
if(OrderMagicNumber()!=M_Number)continue;
if(OrderSymbol()!=Symbol())continue;
if(OrderType()==OP_BUY)
{
double profitPips=Bid-OrderOpenPrice();
double newSL=OrderStopLoss();
if(profitPips>=BE_T_1*point && OrderStopLoss()<OrderOpenPrice()) // Break Even
{
newSL=OrderOpenPrice()+BE_M_1*point;
}
else if(profitPips>=BE_T_3*point) // 150/100
{
newSL=OrderOpenPrice()+BE_M_3*point;
}
else if(profitPips>=BE_T_2*point) // 100/50
{
newSL=OrderOpenPrice()+BE_M_2*point;
}
if(newSL>=OrderStopLoss()+Point && newSL<Bid-stopLevel)
if(!OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(newSL,Digits),OrderTakeProfit(),0))
Print("Error at BE: ",GetLastError());
}
else if(OrderType()==OP_SELL)
{
double profitPips=OrderOpenPrice()-Ask;
double newSL=OrderStopLoss();
if(profitPips>=BE_T_1*point && (OrderStopLoss()>OrderOpenPrice() || OrderStopLoss()==0)) // Break Even
{
newSL=OrderOpenPrice()-BE_M_1*point;
}
else if(profitPips>=BE_T_3*point) // 150/100
{
newSL=OrderOpenPrice()-BE_M_3*point;
}
else if(profitPips>=BE_T_2*point) // 100/50
{
newSL=OrderOpenPrice()-BE_M_2*point;
}
if(newSL<=OrderStopLoss()-Point && newSL>Ask+stopLevel)
if(!OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(newSL,Digits),OrderTakeProfit(),0))
Print("Error at BE: ",GetLastError());
}
}
}
I didn't test this myself in a trade, but it should work.

Creating a Brainfuck parser, whats the best method of parsing loop operators?

I'm creating a Brainfuck parser (in a BASIC dialect) ultimately to create an interpreter but i've realise it's not as straight forward as i first thought. My problem is that i need a way to accurately parse the matching loop operators within a Brainfuck program. This is an example program:
,>,>++++++++[<------<------>>-]
<<[>[>+>+<<-]>>[<<+>>-]<<<-]
>>>++++++[<++++++++>-],<.>.
'[' = start of loop
']' = end of loop
I need to record the start and end point of each matching loop operator so i can jump around the source as needed. Some loops are alone, some are nested.
What would be the best way to parse this? I was thinking maybe move through the source file creating a 2D array (or such like) recording the start and end positions of each matching operator, but this seems like a lot of 'to'ing and fro'ing' through the source. Is this the best way to do it?
More info: Brainfuck homepage
EDIT: Sample code in any language greatly appreciated.
Have you considered using a Stack data structure to record "jump points" (i.e. the location of the instruction pointer).
So basically, every time you encounter a "[" you push the current location of the instruction pointer on this stack. Whenever you encounter a "]" you reset the instruction pointer to the value that's currently on the top of the stack. When a loop is complete, you pop it off the stack.
Here is an example in C++ with 100 memory cells. The code handles nested loops recursively and although it is not refined it should illustrate the concepts..
char cells[100] = {0}; // define 100 memory cells
char* cell = cells; // set memory pointer to first cell
char* ip = 0; // define variable used as "instruction pointer"
void interpret(static char* program, int* stack, int sp)
{
int tmp;
if(ip == 0) // if the instruction pointer hasn't been initialized
ip = program; // now would be a good time
while(*ip) // this runs for as long as there is valid brainF**k 'code'
{
if(*ip == ',')
*cell = getch();
else if(*ip == '.')
putch(*cell);
else if(*ip == '>')
cell++;
else if(*ip == '<')
cell--;
else if(*ip == '+')
*cell = *cell + 1;
else if(*ip == '-')
*cell = *cell - 1;
else if(*ip == '[')
{
stack[sp+1] = ip - program;
*ip++;
while(*cell != 0)
{
interpret(program, stack, sp + 1);
}
tmp = sp + 1;
while((tmp >= (sp + 1)) || *ip != ']')
{
*ip++;
if(*ip == '[')
stack[++tmp] = ip - program;
else if(*ip == ']')
tmp--;
}
}
else if(*ip == ']')
{
ip = program + stack[sp] + 1;
break;
}
*ip++; // advance instruction
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int stack[100] = {0}; // use a stack of 100 levels, modeled using a simple array
interpret(",>,>++++++++[<------<------>>-]<<[>[>+>+<<-]>>[<<+>>-]<<<-]>>>++++++[<++++++++>-],<.>.", stack, 0);
return 0;
}
EDIT
I just went over the code again and I realized there was a bug in the while loop that would 'skip' parsed loops if the value of the pointer is 0. This is where I made the change:
while((tmp >= (sp + 1)) || *ip != ']') // the bug was tmp > (sp + 1)
{
ip++;
if(*ip == '[')
stack[++tmp] = ip - program;
else if(*ip == ']')
tmp--;
}
Below is an implementation of the same parser but without using recursion:
char cells[100] = {0};
void interpret(static char* program)
{
int cnt; // cnt is a counter that is going to be used
// only when parsing 0-loops
int stack[100] = {0}; // create a stack, 100 levels deep - modeled
// using a simple array - and initialized to 0
int sp = 0; // sp is going to be used as a 'stack pointer'
char* ip = program; // ip is going to be used as instruction pointer
// and it is initialized at the beginning or program
char* cell = cells; // cell is the pointer to the 'current' memory cell
// and as such, it is initialized to the first
// memory cell
while(*ip) // as long as ip point to 'valid code' keep going
{
if(*ip == ',')
*cell = getch();
else if(*ip == '.')
putch(*cell);
else if(*ip == '>')
cell++;
else if(*ip == '<')
cell--;
else if(*ip == '+')
*cell = *cell + 1;
else if(*ip == '-')
*cell = *cell - 1;
else if(*ip == '[')
{
if(stack[sp] != ip - program)
stack[++sp] = ip - program;
*ip++;
if(*cell != 0)
continue;
else
{
cnt = 1;
while((cnt > 0) || *ip != ']')
{
*ip++;
if(*ip == '[')
cnt++;
else if(*ip == ']')
cnt--;
}
sp--;
}
}else if(*ip == ']')
{
ip = program + stack[sp];
continue;
}
*ip++;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
// define our program code here..
char *prg = ",>++++++[<-------->-],[<+>-]<.";
interpret(prg);
return 0;
}
Interesting enough, just a couple days ago, I was writing a brainf*ck interpreter in Java.
One of the issues I was having was that the explanation of the commands at the official page was insufficient, and did not mention the part about nested loops. The Wikipedia page on Brainf*ck has a Commands subsection which describes the correct behavior.
Basically to summarize the problem, the official page says when an instruction is a [ and the current memory location is 0, then jump to the next ]. The correct behavior is to jump to the corresponding ], not the next one.
One way to achieve this behavior is to keep track of the level of nesting. I ended up implementing this by having a counter which kept track of the nesting level.
The following is part of the interpreter's main loop:
do {
if (inst[pc] == '>') { ... }
else if (inst[pc] == '<') { ... }
else if (inst[pc] == '+') { ... }
else if (inst[pc] == '-') { ... }
else if (inst[pc] == '.') { ... }
else if (inst[pc] == ',') { ... }
else if (inst[pc] == '[') {
if (memory[p] == 0) {
int nesting = 0;
while (true) {
++pc;
if (inst[pc] == '[') {
++nesting;
continue;
} else if (nesting > 0 && inst[pc] == ']') {
--nesting;
continue;
} else if (inst[pc] == ']' && nesting == 0) {
break;
}
}
}
}
else if (inst[pc] == ']') {
if (memory[p] != 0) {
int nesting = 0;
while (true) {
--pc;
if (inst[pc] == ']') {
++nesting;
continue;
} else if (nesting > 0 && inst[pc] == '[') {
--nesting;
continue;
} else if (inst[pc] == '[' && nesting == 0) {
break;
}
}
}
}
} while (++pc < inst.length);
Here is the legend for the variable names:
memory -- the memory cells for the data.
p -- pointer to the current memory cell location.
inst -- an array holding the instructions.
pc -- program counter; points to the current instruction.
nesting -- level of the nesting of the current loop. nesting of 0 means that the current location is not in a nested loop.
Basically, when a loop opening [ is encountered, the current memory location is checked to see if the value is 0. If that is the case, a while loop is entered to jump to the corresponding ].
The way the nesting is handled is as follows:
If an [ is encountered while seeking for the corresponding loop closing ], then the nesting variable is incremented by 1 in order to indicate that we have entered a nested loop.
If an ] is encountered, and:
a. If the nesting variable is greater than 0, then the nesting variable is decremented by 1 to indicate that we've left a nested loop.
b. If the nesting variable is 0, then we know that the end of the loop has been encountered, so seeking the end of the loop in the while loop is terminated by executing a break statement.
Now, the next part is to handle the closing of the loop by ]. Similar to the opening of the loop, it will use the nesting counter in order to determine the current nesting level of the loop, and try to find the corresponding loop opening [.
This method may not be the most elegant way to do things, but it seems like it is resource-friendly because it only requires one extra variable to use as a counter for the current nesting level.
(Of course, "resource-friendly" is ignoring the fact that this interpreter was written in Java -- I just wanted to write some quick code and Java just happened to be what I wrote it in.)
The canonical method for parsing a context-free grammar is to use a stack. Anything else and you're working too hard and risking correctness.
You may want to use a parser generator like cup or yacc, as a lot of the dirty work is done for you, but with a language as simple as BF, it may be overkill.
Each time you find a '[', push the current position (or another "marker" token or a "context") on a stack. When you come accross a ']', you're at the end of the loop, and you can pop the marker token from the stack.
Since in BF the '[' already checks for a condition and may need jump past the ']', you may want to have a flag indicating that instructions shall be skipped in the current loop context.
Python 3.0 example of the stack algorithm described by the other posters:
program = """
,>,>++++++++[<------<------>>-]
<<[>[>+>+<<-]>>[<<+>>-]<<<-]
>>>++++++[<++++++++>-],<.>.
"""
def matching_brackets(program):
stack = []
for p, c in enumerate(program, start=1):
if c == '[':
stack.append(p)
elif c == ']':
yield (stack.pop(), p)
print(list(matching_brackets(''.join(program.split()))))
(Well, to be honest, this only finds matching brackets. I don't know brainf*ck, so what to do next, I have no idea.)
And here's the same code I gave as an example earlier in C++, but ported to VB.NET. I decided to post it here since Gary mentioned he was trying to write his parser in a BASIC dialect.
Public cells(100) As Byte
Sub interpret(ByVal prog As String)
Dim program() As Char
program = prog.ToCharArray() ' convert the input program into a Char array
Dim cnt As Integer = 0 ' a counter to be used when skipping over 0-loops
Dim stack(100) As Integer ' a simple array to be used as stack
Dim sp As Integer = 0 ' stack pointer (current stack level)
Dim ip As Integer = 0 ' Instruction pointer (index of current instruction)
Dim cell As Integer = 0 ' index of current memory
While (ip < program.Length) ' loop over the program
If (program(ip) = ",") Then
cells(cell) = CByte(AscW(Console.ReadKey().KeyChar))
ElseIf (program(ip) = ".") Then
Console.Write("{0}", Chr(cells(cell)))
ElseIf (program(ip) = ">") Then
cell = cell + 1
ElseIf (program(ip) = "<") Then
cell = cell - 1
ElseIf (program(ip) = "+") Then
cells(cell) = cells(cell) + 1
ElseIf (program(ip) = "-") Then
cells(cell) = cells(cell) - 1
ElseIf (program(ip) = "[") Then
If (stack(sp) <> ip) Then
sp = sp + 1
stack(sp) = ip
End If
ip = ip + 1
If (cells(cell) <> 0) Then
Continue While
Else
cnt = 1
While ((cnt > 0) Or (program(ip) <> "]"))
ip = ip + 1
If (program(ip) = "[") Then
cnt = cnt + 1
ElseIf (program(ip) = "]") Then
cnt = cnt - 1
End If
End While
sp = sp - 1
End If
ElseIf (program(ip) = "]") Then
ip = stack(sp)
Continue While
End If
ip = ip + 1
End While
End Sub
Sub Main()
' invoke the interpreter
interpret(",>++++++[<-------->-],[<+>-]<.")
End Sub
I don't have sample code, but.
I might try using a stack, along with an algorithm like this:
(executing instruction stream)
Encounter a [
If the pointer == 0, then keep reading until you encounter the ']', and don't execute any instructions until you reach it.. Goto step 1.
If the pointer !=0, then push that position onto a stack.
Continue executing instructions
If you encounter a ]
If pointer==0, pop the [ off of the stack, and proceed (goto step 1)
If pointer != 0, peek at the top of the stack, and go to that position. (goto step 5)
This question is a bit old, but I wanted to say that the answers here helped me decide the route to take when writing my own Brainf**k interpreter. Here's the final product:
#include <stdio.h>
char *S[9999], P[9999], T[9999],
**s=S, *p=P, *t=T, c, x;
int main() {
fread(p, 1, 9999, stdin);
for (; c=*p; ++p) {
if (c == ']') {
if (!x)
if (*t) p = *(s-1);
else --s;
else --x;
} else if (!x) {
if (c == '[')
if (*t) *(s++) = p;
else ++x;
}
if (c == '<') t--;
if (c == '>') t++;
if (c == '+') ++*t;
if (c == '-') --*t;
if (c == ',') *t = getchar();
if (c == '.') putchar(*t);
}
}
}
package interpreter;
import java.awt.event.ActionListener;
import javax.swing.JTextPane;
public class Brainfuck {
final int tapeSize = 0xFFFF;
int tapePointer = 0;
int[] tape = new int[tapeSize];
int inputCounter = 0;
ActionListener onUpdateTape;
public Brainfuck(byte[] input, String code, boolean debugger,
JTextPane output, ActionListener onUpdate) {
onUpdateTape = onUpdate;
if (debugger) {
debuggerBF(input, code, output);
} else {
cleanBF(input, code, output);
}
}
private void debuggerBF(byte[] input, String code, JTextPane output) {
for (int i = 0; i < code.length(); i++) {
onUpdateTape.actionPerformed(null);
switch (code.charAt(i)) {
case '+': {
tape[tapePointer]++;
break;
}
case '-': {
tape[tapePointer]--;
break;
}
case '<': {
tapePointer--;
break;
}
case '>': {
tapePointer++;
break;
}
case '[': {
if (tape[tapePointer] == 0) {
int nesting = 0;
while (true) {
++i;
if (code.charAt(i) == '[') {
++nesting;
continue;
} else if (nesting > 0 && code.charAt(i) == ']') {
--nesting;
continue;
} else if (code.charAt(i) == ']' && nesting == 0) {
break;
}
}
}
break;
}
case ']': {
if (tape[tapePointer] != 0) {
int nesting = 0;
while (true) {
--i;
if (code.charAt(i) == ']') {
++nesting;
continue;
} else if (nesting > 0 && code.charAt(i) == '[') {
--nesting;
continue;
} else if (code.charAt(i) == '[' && nesting == 0) {
break;
}
}
}
break;
}
case '.': {
output.setText(output.getText() + (char) (tape[tapePointer]));
break;
}
case ',': {
tape[tapePointer] = input[inputCounter];
inputCounter++;
break;
}
}
}
}
private void cleanBF(byte[] input, String code, JTextPane output) {
for (int i = 0; i < code.length(); i++) {
onUpdateTape.actionPerformed(null);
switch (code.charAt(i)) {
case '+':{
tape[tapePointer]++;
break;
}
case '-':{
tape[tapePointer]--;
break;
}
case '<':{
tapePointer--;
break;
}
case '>':{
tapePointer++;
break;
}
case '[': {
if (tape[tapePointer] == 0) {
int nesting = 0;
while (true) {
++i;
if (code.charAt(i) == '[') {
++nesting;
continue;
} else if (nesting > 0 && code.charAt(i) == ']') {
--nesting;
continue;
} else if (code.charAt(i) == ']' && nesting == 0) {
break;
}
}
}
break;
}
case ']': {
if (tape[tapePointer] != 0) {
int nesting = 0;
while (true) {
--i;
if (code.charAt(i) == ']') {
++nesting;
continue;
} else if (nesting > 0 && code.charAt(i) == '[') {
--nesting;
continue;
} else if (code.charAt(i) == '[' && nesting == 0) {
break;
}
}
}
break;
}
case '.':{
output.setText(output.getText()+(char)(tape[tapePointer]));
break;
}
case ',':{
tape[tapePointer] = input[inputCounter];
inputCounter++;
break;
}
}
}
}
public int[] getTape() {
return tape;
}
public void setTape(int[] tape) {
this.tape = tape;
}
public void editTapeValue(int counter, int value) {
this.tape[counter] = value;
}
}
This should work. You need to modify it somewhat.
That is actually standard example how brainfuck interpreter works. I modified it to use in my app, brackets are handled there:
case '[': {
if (tape[tapePointer] == 0) {
int nesting = 0;
while (true) {
++i;
if (code.charAt(i) == '[') {
++nesting;
continue;
}
else if (nesting > 0 && code.charAt(i) == ']') {
--nesting;
continue;
}
else if (code.charAt(i) == ']' && nesting == 0) {
break;
}
}
}
break;
}
case ']': {
if (tape[tapePointer] != 0) {
int nesting = 0;
while (true) {
--i;
if (code.charAt(i) == ']') {
++nesting;
continue;
}
else if (nesting > 0 && code.charAt(i) == '[') {
--nesting;
continue;
}
else if (code.charAt(i) == '[' && nesting == 0) {
break;
}
}
}
break;
}
It looks like this question has become a "post your bf interpreter" poll.
So here's mine that I just got working:
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
void error(char *msg) {
fprintf(stderr, "Error: %s\n", msg);
}
enum { MEMSIZE = 30000 };
char *mem;
char *ptr;
char *prog;
size_t progsize;
int init(char *progname) {
int f,r;
struct stat fs;
ptr = mem = calloc(MEMSIZE, 1);
f = open(progname, O_RDONLY);
assert(f != -1);
r = fstat(f, &fs);
assert(r == 0);
prog = mmap(NULL, progsize = fs.st_size, PROT_READ, MAP_PRIVATE, f, 0);
assert(prog != NULL);
return 0;
}
int findmatch(int ip, char src){
char *p="[]";
int dir[]= { 1, -1 };
int i;
int defer;
i = strchr(p,src)-p;
ip+=dir[i];
for (defer=dir[i]; defer!=0; ip+=dir[i]) {
if (ip<0||ip>=progsize) error("mismatch");
char *q = strchr(p,prog[ip]);
if (q) {
int j = q-p;
defer+=dir[j];
}
}
return ip;
}
int run() {
int ip;
for(ip = 0; ip>=0 && ip<progsize; ip++)
switch(prog[ip]){
case '>': ++ptr; break;
case '<': --ptr; break;
case '+': ++*ptr; break;
case '-': --*ptr; break;
case '.': putchar(*ptr); break;
case ',': *ptr=getchar(); break;
case '[': /*while(*ptr){*/
if (!*ptr) ip=findmatch(ip,'[');
break;
case ']': /*}*/
if (*ptr) ip=findmatch(ip,']');
break;
}
return 0;
}
int cleanup() {
free(mem);
ptr = NULL;
return 0;
}
int main(int argc, char *argv[]) {
init(argc > 1? argv[1]: NULL);
run();
cleanup();
return 0;
}

Resources