Recursive Descent Parser - c++

The book 'Modern Compiler Design' is the nice book about compilers. In its source code something that is annoying me is AST or Abstract Syntax Tree. Suppose we want to write a parenthesized expression parser which parses something like: ((2+3)*4) * 2! The book says that we have an AST like:
((2+3)*4) * 2
/ | \
(2+3) *4 * 2
/ | \
(2+3) * 4
/ | \
2 + 3
So should I save a tree in memory or just use recursive calls; Note: if I don't store it in memory, how can I convert it to machine code ?
Parser code:
int parse(Expression &expr)
{
if(token.class=='D')
{
expr.type='D';
expr.value=token.val-'0';
get_next_token();
return 1;
}
if(token.class=='(')
{
expr.type='P';
get_next_token();
parse(&expr->left);
parse_operator(&expr->op);
parse(&expr->right);
if(token.class!=')')
Error("missing )");
get_next_token();
return 1;
}
return 0;
}
Grammar is:
expr -> expr | (expr op expr)
digit -> 0|1|2....|9
op -> +|*

You can store the tree in memory or you can directly produce the required output code. Storing the intermediate form is normally done to be able to do some processing on the code at an higher level before generating output.
In your case for example it would be simple to discover that your expression contains no variables and therefore the result is a fixed number. Looking only at one node at a time this however is not possible. To be more explicit if after looking at "2*" you generate machine code for computing the double of something this code is sort of wasted when the other part is for example "3" because your program will compute "3" and then compute the double of that every time while just loading "6" would be equivalent but shorter and faster.
If you want to generate the machine code then you need first to know for what kind of machine the code is going to be generated... the simplest model uses a stack-based approach. In this case you need no register allocation logic and it's easy to compile directly to machine code without the intermediate representation. Consider this small example that handles just integers, four operations, unary negation and variables... you will notice that no data structure is used at all: source code characters are read and machine instructions are written to output...
#include <stdio.h>
#include <stdlib.h>
void error(const char *what) {
fprintf(stderr, "ERROR: %s\n", what);
exit(1);
}
void compileLiteral(const char *& s) {
int v = 0;
while (*s >= '0' && *s <= '9') {
v = v*10 + *s++ - '0';
}
printf(" mov eax, %i\n", v);
}
void compileSymbol(const char *& s) {
printf(" mov eax, dword ptr ");
while ((*s >= 'a' && *s <= 'z') ||
(*s >= 'A' && *s <= 'Z') ||
(*s >= '0' && *s <= '9') ||
(*s == '_')) {
putchar(*s++);
}
printf("\n");
}
void compileExpression(const char *&);
void compileTerm(const char *& s) {
if (*s >= '0' && *s <= '9') {
// Number
compileLiteral(s);
} else if ((*s >= 'a' && *s <= 'z') ||
(*s >= 'A' && *s <= 'Z') ||
(*s == '_')) {
// Variable
compileSymbol(s);
} else if (*s == '-') {
// Unary negation
s++;
compileTerm(s);
printf(" neg eax\n");
} else if (*s == '(') {
// Parenthesized sub-expression
s++;
compileExpression(s);
if (*s != ')')
error("')' expected");
s++;
} else {
error("Syntax error");
}
}
void compileMulDiv(const char *& s) {
compileTerm(s);
for (;;) {
if (*s == '*') {
s++;
printf(" push eax\n");
compileTerm(s);
printf(" mov ebx, eax\n");
printf(" pop eax\n");
printf(" imul ebx\n");
} else if (*s == '/') {
s++;
printf(" push eax\n");
compileTerm(s);
printf(" mov ebx, eax\n");
printf(" pop eax\n");
printf(" idiv ebx\n");
} else break;
}
}
void compileAddSub(const char *& s) {
compileMulDiv(s);
for (;;) {
if (*s == '+') {
s++;
printf(" push eax\n");
compileMulDiv(s);
printf(" mov ebx, eax\n");
printf(" pop eax\n");
printf(" add eax, ebx\n");
} else if (*s == '-') {
s++;
printf(" push eax\n");
compileMulDiv(s);
printf(" mov ebx, eax\n");
printf(" pop eax\n");
printf(" sub eax, ebx\n");
} else break;
}
}
void compileExpression(const char *& s) {
compileAddSub(s);
}
int main(int argc, const char *argv[]) {
if (argc != 2) error("Syntax: simple-compiler <expr>\n");
compileExpression(argv[1]);
return 0;
}
For example running the compiler with 1+y*(-3+x) as input you get as output
mov eax, 1
push eax
mov eax, dword ptr y
push eax
mov eax, 3
neg eax
push eax
mov eax, dword ptr x
mov ebx, eax
pop eax
add eax, ebx
mov ebx, eax
pop eax
imul ebx
mov ebx, eax
pop eax
add eax, ebx
However this approach of writing compilers doesn't scale well to an optimizing compiler.
While it's possible to get some optimization by adding a "peephole" optimizer in the output stage, many useful optimizations are possible only looking at code from an higher point of view.
Also even the bare machine code generation could benefit by seeing more code, for example to decide which register assign to what or to decide which of the possible assembler implementations would be convenient for a specific code pattern.
For example the same expression could be compiled by an optimizing compiler to
mov eax, dword ptr x
sub eax, 3
imul dword ptr y
inc eax

Nine times out of ten you'll save the AST in memory for whatever you are doing after lexing and parsing are done.
Once you have an AST you can do a number of things:
Evaluate it directly (perhaps using recursion, perhaps using your own custom stack)
Transform it into some other output, such as code in another language or some other type of translation.
Compile it to preferred instruction set
etc.

You can create an AST with Dijkstra's Shunting-yard algorithm.
At some point you will have the whole expression or AST in memory though, unless you calculate immediate results while parsing. This works with (sub-)expressions containing only literals or compile time constants, but not with any variables calculated at runtime.

So should I save a tree in memory or just use recursive calls;
You'll use recursive calls in your parser to build the tree in memory.
And of course, you want to keep the tree in memory to process it.
An optimizing compiler keeps several representations of the code in memory (and transform them).

The answer to the question depends on whether you want a compiler, an interpreter, or something in between (an interpreter wrapped around an intermediate language). If you want an interpreter, a recursive descent parser will at the same time evaluate the expression, so there is no need to hold it in memory. If you want a compiler, then a constant expression like the example can and should be optimised, but most expressions will operate on variables, and you need to convert to tree form as an intermediate step before converting to a linear form.
A hybrid compiler / interpreter will usually compile expressions, but it doesn't have to. It's often a cheap way of writing a program which outputs an executable to simply wrap the interpreter up with the source code. Matlab uses this technique - code used to be genuinely compiled but there were problems with consistency with the interactive version. However I wouldn't allow the difficulty of generating a parse tree for expressions determine the issue.

Related

How to pass an array reference as a parameter from assembly to a c++ function

I have two separate files in two Visual Studio 2012 projects. One is MASM and the other is C++. The MASM program is supposed to call the DisplayBoard function in the C++ program and needs to pass a reference to the array it is displaying. I can't figure out what exactly I need to do to make this work. The program was created in its entirety as a C++ program and works the way it should, but we are supposed to do the majority of coding in MASM and have minimal C++ functions, so we are trying to get these two files talking but are having issues. Here are the skeleton codes for my MASM and C++ Files. I am not sure if the C++ file needs a main, but it does compile without one. Also, does the board array need to be declared in the C++ file if it is passed in as a parameter? I think it doesn't, but am not sure. I don't know if the array parameter is referenced correctly in the C++ file or not.
ASSEMBLY CODE:
TITLE HexAssemblyTest (HexAssemblyTest.asm)
.586
.model flat,C
includelib kernel32.lib
includelib Irvine32.lib
ShowBoard PROTO near C, hexBoard:SDWORD
.data
board SDWORD 121 DUP (0) ;array to hold the hex board
.code
main PROC
INVOKE ShowBoard, ADDR board ;display board
Retn
main ENDP
END main
C++ CODE:
#include "stdafx.h"
#include<iostream>
#include<iomanip>
#include<Windows.h>
#include<stack>
using namespace std;
extern "C" void showBoard(int hex_array[]);
//Class DFS definition
class DFSAlgorithm{
public:
int board[121]; //board array
//function to display the board
void showBoard(int hex_array[]){
//code here...
}
//other functions...removed
}
};//end DFSAlgorithm class
This is the error we get:
------ Build started: Project: HexAssembly, Configuration: Debug Win32 ------
1> Assembling HexAssemblyTest.asm...
1>HexAssemblyTest.obj : error LNK2019: unresolved external symbol _ShowBoard referenced in function _main
1>C:\Irvine\Examples\Assembly Hex programming\Debug\HexAssembly.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
I think I got it working correctly now... I modified DFSAlgorithm.cpp and DFSAlgorithm.h, compiled the C++ file and added DFSAlsogrithm.obj file to the project that has the assembly file. They are now linking, but I'm getting a "deque iterator not dereferenceable" error message now when the C++ DFS search runs. It worked fine while the entire program was in C++ so I'm not sure what I need to change to make it work correctly now that the array is being accessed from assembly file. While stepping through with my debugger, I can see it IS generating adjacency arrays but I don't think the array is actually being accessed...
TITLE HexAssemblyTest (HexAssemblyTest.asm)
INCLUDE Irvine32.inc
printSomething PROTO C ;displays "GoobersX"
DFS PROTO C, color:BYTE, bptr:PTR DWORD, index:SDWORD
PDWORD TYPEDEF PTR DWORD
.data
bptr PDWORD board
board SDWORD 121 DUP (0) ;array to hold the hex board
arrayIndex SDWORD 0 ;variable to hold arrayIndex
.code
main PROC
INVOKE printSomething ;tests if MASM and C++ are talking
Start:
CALL PlaceRed ;prompt user to place a red stone
CALL clrscr
CALL crlf
CALL ShowBoard ;redraw the board
;check if there is a valid path using C++ DFS
PUSH EDX
PUSH EBX
PUSH ECX
INVOKE DFS, 1, ADDR board, 0 ;color red, board address, arrayIndex 0
POP ECX
POP EBX
POP EDX
CMP EAX,1 ;if eAx == 1 winning path found
JNE Continue ;eAx != 1 no valid path...continue game
;the rest of this code removed for brevity
END_GAME:
Retn
main ENDP
My C++ header file looks like this:
C++ header file DFSAlgorithm.h
#ifndef DFSAlgorithm_H
#define DFSAlgorithm_H
extern "C" void printSomething();
extern "C" int DFS(int color, int hex_array[], int array_index);
#endif
And my C++ cpp file (abbreviated) looks like this:
#include "stdafx.h"
#include<iostream>
#include<stack>
#include "DFSAlgorithm.h"//include definition of class DFSAlgorithm
using namespace std;
int adjacency[6];
stack<int> path; //stack to hold the last hex visited
//test printsomething
extern "C" void printSomething(){
cout<<"Goobers2014";
}
//First call of DFS always starts with array_index == 0
extern "C" int DFS(int color, int hex_array[], int array_index){
if (hex_array[array_index] == color){ //if hex has an appropriately colored stone
hex_array[array_index] += 3; //mark the hex as visited
path.push(array_index); //push hex onto path stack
}
if ((color == 1 && array_index % 11 == 10 && hex_array[array_index] == 4) ||
(color == 2 && array_index / 11 == 10 && hex_array[array_index] == 5)){
return 1; //winner base case==>reached the other side
}
//If a visited/unvisited hex has a stone of correct color==> search adjacent hexes
if ((color == 1 && hex_array[array_index] == 4) ||
(color == 2 && hex_array[array_index] == 5)){
//get adjacencies
//removed from code for brevity
}
/*Initialize adjacentHexes to zero: if == 0 after all 6 adjacencies are
checked it is a dead end as there are no unvisited adjacent hexes with
the correct color stone*/
int adjacentHexes = 0;
for(int b = 0; b < 6; b++){//traverse adjacency array of passed in index
//if one of the adjacent hexes has a red/blue stone
if((color == 1 && hex_array[adjacency[b]] == color) ||
(color == 2 && hex_array[adjacency[b]] == color )){
adjacentHexes++; //increment adjacentHexes count
hex_array[adjacency[b]] += 3; //mark the hex as visited
path.push(adjacency[b]); //push visited adjacent hex onto path
//recursively call DFS with that adjacent hex index
return DFS(color, hex_array,adjacency[b]);
}
}
//If adjacentHexes == 0 ==> dead-end
if(adjacentHexes == 0 && path.size() > 1){
path.pop();//pop the top hex from the stack if stack > 1
//recursive call of DFS with the new top red/blue hex
return DFS(color, hex_array,path.top());
}
if(adjacentHexes == 0 && path.size() == 1){//back to Row 0/Column 0
//make the array_index = the top of the path stack
//+++++this line generates a "deque iterator not dereferenceable" error++++++++++++++
array_index = path.top();
//pop remaining element from the stack so path is now zero
path.pop();
}
}
//if checking for a red path and path is empty
if (color == 1 ){
//search remaining column 0 hexes for unvisited red hex
for(array_index ; array_index <= 99; ){
//recursively call DFS with next Column 0 hex
return DFS(color, hex_array, array_index + 11);
}
}
//if checking for a blue path and path is empty
if (color == 2){
//search remaining row 0 hexes for unvisted blue hex
for(array_index ; array_index <= 9; ){
//recursively call DFS with next Row 0 hex
return DFS(color, hex_array, array_index + 1);
}
}
//Traverse hex_array and reset all visited hexes to unvisited
for(int a = 0; a < 121; a++){
if(hex_array[a] >= 4)//if hex has been visited
hex_array[a] -= 3;//remove visited designation
}
return -1;//return false as no path exists
}
I'm not sure why it fails on the line where I set the array_index to path.top() and then pop the top off the stack because it worked fine when the entire file was in C++ so I'm not sure why it is not working now. I assume it has something to do with how the C++ function is accessing the array_index.
The error tells you the problem very clearly; you have no definition of global function ShowBoard.
If you were expecting DFSAlgorithm::showBoard's definition, then you will be disappointed for two reasons:
DFSAlgorithm::showBoard is not a global function, but a member function (on which instance of DFSAlgorithm would it operate?);
showBoard and ShowBoard are spelt differently.
As for main, your C++ file should not define main because your assembly file does, and you only want one such definition across your program.

Passing pointers to function without copying it

How do I pass data around my program without copying it every time?
Specifically, when calling sim(ohlc) I want to just pass the pointer reference, I don't want to copy the data to the function.
This is the program I made, but I'm not sure this is the best way to do it (specially when it comes to speed and memory usage).
I think I'm not passing the pointer to sim(ohlc) like I should, but if I try sim(&ohlc) I don't know how to change the sim function to accept that.
struct ohlcS {
vector<unsigned int> timestamp;
vector<float> open;
vector<float> high;
vector<float> low;
vector<float> close;
vector<float> volume;
} ;
ohlcS *read_csv(string file_name) {
// open file and read stuff
if (read_error)
return NULL;
static ohlcS ohlc;
ohlc.timestamp.push_back(read_value);
return &ohlc;
}
int sim(ohlcS* ohlc) {
// do stuff
return 1;
}
main() {
ohlcS *ohlc = read_csv(input_file);
results = sim(ohlc);
}
It's C++, use a reference. It's safe, since you return a static object.
static ohlc ohlc_not_found;
ohlc &read_csv(string file_name) {
// open file and read stuff
if(error_while_opening)
{
return ohlc_not_found;
}
static ohlc loc_ohlc;
loc_ohlc.timestamp.push_back(read_value);
return loc_ohlc;
}
int sim(const ohlc& par_ohlc) {
// do stuff
return 1;
}
....
ohlc& var_ohlc = read_csv(input_file);
if(var_ohlc == ohlc_not_found)
{
// error handling
return;
}
results = sim(var_ohlc);
If you want to modify par_ohlc in sim, do not make it const.
and it's not recommended to use ohlc for both class and variable name :(
In line:
results = sim(ohlc);
you are passing ohlc pointer to sim function, no deep data copy is done, only 32bit pointer value is copied.
This pushes the address (32 bit value) onto the stack.
results = sim(ohlc);
Like:
; ...
push eax ; addr of struct/class/whatever
call function ; jump to function
; ...
function:
push ebp
mov ebp, esp
mov eax, [ebp+8] ; ebp+8 is the 32 bit value you pushed before onto the stack
; -> your pointer
Take a look at this and maybe that too.
Version 2
; ...
push eax ; addr of struct/class/whatever
jmp function ; jump to function
autolbl001:
; ...
function:
push ebp
mov ebp, esp
mov eax, [ebp+8] ; ebp+8 is the 32 bit value you pushed before onto the stack
; ...
jmp autolbl001

Pointer to element in an 2D array slows down code

I have this piece of code which accesses some information about a point on a 'x' and 'y' axis. This information is later used to draw some points onto the screen.
This is how the code works:
//MAX_X_COORD has a value of 169
//MAX_Y_COORD has a value of 55
void RedrawFromDATAtable()
{
COORD pos;
HANDLE tmpbuf = CreateConsoleScreenBuffer(GENERIC_WRITE , NULL, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
WriteConsoleA(tmpbuf, " ", 1, NULL, NULL);
if(SetConsoleActiveScreenBuffer(tmpbuf)==0)
{MessageBoxA(NULL, "ERROR", "ERROR", 0);return;}
bufferdata_ex * dptr;
//bufferdata_ex * y_dptr;
int * lcol(new int); //Increases speed by reducing function calls - Experienced about twice as fast drawing!
for(short x=0;x<MAX_X_COORD;x++)
{
//y_dptr = bridge->DATA[x];
for(short y=0;y<MAX_Y_COORD;y++)
{
//dptr = (y_dptr+y); //Rewrite to use a constant pointer!
dptr = &(_bridge->DATA[x][y]);
if(dptr->InUse==true)
{
{
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(output, pos);
//haschanged = false;
}
if(!(*lcol==dptr->color)) //Need for a new color?
{ SetConsoleTextAttribute(output, dptr->color);lcol = &dptr->color;}
char c((char)dptr->sym);
WriteConsoleA(output, &c, 1, NULL, NULL);
lcol = &dptr->color;
}
}
}
SetConsoleTextAttribute(output, bridge->current_color);
SetConsoleCursorPosition(output, last_mouse_position);
SetConsoleActiveScreenBuffer(output);
CloseHandle(tmpbuf);
delete lcol;
}
Cut to the case!
Alright!
So recently I had a thought that accessing the array like that would slow down my code. As far as I know then whenever you access an element in an array the processor will take the base adress of the array and from there by multiply the size of the elements by the index which is used to find the adress of the specified element.
My thought here was that if I ask the processor to do that multiple times, instead of just creating a pointer to the adress, and then use that to process my elements, then it would slow down my code.
So I rewrote the code to the following:
void RedrawFromDATAtable()
{
COORD pos;
HANDLE tmpbuf = CreateConsoleScreenBuffer(GENERIC_WRITE , NULL, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
WriteConsoleA(tmpbuf, " ", 1, NULL, NULL);
if(SetConsoleActiveScreenBuffer(tmpbuf)==0)
{MessageBoxA(NULL, "ERROR", "ERROR", 0);return;}
bufferdata_ex * dptr;
bufferdata_ex * y_dptr;
int * lcol(new int); //Increases speed by reducing function calls - Experienced about twice as fast drawing!
for(short x=0;x<MAX_X_COORD;x++)
{
y_dptr = _bridge->DATA[x];
for(short y=0;y<MAX_Y_COORD;y++)
{
dptr = (y_dptr+y); //Rewrite to use a constant pointer!
//dptr = &(bridge->DATA[x][y]);
if(dptr->InUse==true)
{
{
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(output, pos);
//haschanged = false;
}
if(!(*lcol==dptr->color)) //Need for a new color?
{ SetConsoleTextAttribute(output, dptr->color);lcol = &dptr->color;}
char c((char)dptr->sym);
WriteConsoleA(output, &c, 1, NULL, NULL);
lcol = &dptr->color;
}
}
}
SetConsoleTextAttribute(output, bridge->current_color);
SetConsoleCursorPosition(output, last_mouse_position);
SetConsoleActiveScreenBuffer(output);
CloseHandle(tmpbuf);
delete lcol;
}
The idea seems perfectly fine to me, but the problem is that the first piece of code is faster than the second piece of code!
So my question is: Why is it the first piece of code is faster than the second piece of code?
For those who doesn't like to read:
Why is the first piece of code faster than the other?
The first one takes 0.0919 seconds to finish where the second takes 0.226 seconds.
Also this is a copy of how the assembly handles the pointers:
//No pointers
dptr = &(bridge->DATA[x][y]);
001B41C6 mov eax,dword ptr [this]
001B41C9 mov ecx,dword ptr [eax+14h]
001B41CC movsx edx,word ptr [x]
001B41D0 imul edx,edx,370h
001B41D6 lea eax,[ecx+edx+1D4h]
001B41DD movsx ecx,word ptr [y]
001B41E1 shl ecx,4
001B41E4 add eax,ecx
001B41E6 mov dword ptr [dptr],eax
//With pointers
//Pointing to DATA[x]
012C41A5 mov eax,dword ptr [this]
012C41A8 mov ecx,dword ptr [eax+14h]
012C41AB movsx edx,word ptr [x]
012C41AF imul edx,edx,370h
012C41B5 lea eax,[ecx+edx+1D4h]
012C41BC mov dword ptr [y_dptr],eax
//Pointing to DATA[x]+y
012C41E0 movsx eax,word ptr [y]
012C41E4 shl eax,4
012C41E7 add eax,dword ptr [y_dptr]
012C41EA mov dword ptr [dptr],eax
other than this part of the code, then the rest is identical.
Looking only at the assembly we see an extra mov (the assignment of y_dptr).
Seeing how this is done on every iteration in the (outer) loop and there are no other differences in the code, this could be your reason for performance decrease.
Other than that, there is really nothing in your code that takes advantage of the pointer magic you are trying to use.
f.e. You use dptr = (y_dptr+y); where you can lose either dptr or y_dptr by using increment on the pointer directly (y_dptr++;). This is some pointer arithmetic magic you are not using and could be improved.

Does this qualify as tail recursion? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Tail recursion in C++
I'm new to tail recursion in c++. My project requires I make all my functions tail recursive. I've tested the following code and it works correctly. However, I'm not sure if how I've done it qualifies as tail recursion.
static int sum_helper(list_t hList, int accumulator){
if (list_isEmpty(hList))
return accumulator;
else {
accumulator += list_first(hList);
hList = list_rest(hList);
return sum_helper(hList, accumulator);
}
}
int sum(list_t list){
/*
// EFFECTS: returns the sum of each element in list
// zero if the list is empty.
*/
if (list_isEmpty(list))
return 0;
return sum_helper(list, 0);
}
Thanks!
In short, you don't do anything after the recursive call (sum_helper). This means that you never need to return to the caller, and thus, you can throw away the stack frame of the caller.
Take the example of the normal factorial function
int fact(int x)
{
if(x == 0)
return 1;
else
return x * fact(x-1);
}
This is not tail recursive since the value of fact(x-1) needs to be returned, then multiplied by six. Instead, we can cheat a little, and pass an accumulator too. See this:
int fact(int x, int acc)
{
if(x == 0)
return acc; // Technically, acc * 1, but that's the identity anyway.
else
return fact(x-1, acc*x);
}
Here, the last function call in the control flow is fact(x-1, acc*x). Afterwards, we don't need to use the return value for anything of the called function for anything else, hence we don't need to return to the current frame. For this reason, we can throw away the stack frame and apply other optimisations.
Disclaimer: I've probably applied the factorial algorithm wrong, but you get the jist. Hopefully.
It's tail-recursion provided list_t doesn't have a non-trivial destructor. If it does have a non-trivial destructor, the destructor needs to run after the recursive call returns and before the function itself returns.
Bonus:
int sum(list_t hList, int accumulator = 0) {
return list_isEmpty(hList)
? 0
: sum(list_rest(hList), accumulator + list_first(hList));
}
But tastes vary; some people might like yours more.
From theoreitcal point of view, yes, it's tail recursion (provided that hList does not have nontrival destructor). But from practival point of view it depends on your compiler and its settings. Let's take a look at assembly generated for this simple code:
#include <cstdlib>
struct list{
int head;
list * tail;
};
int sum_helper(list * l, int accumulator){
if (l == NULL)
return accumulator;
else {
accumulator += l->head;
return sum_helper(l->tail, accumulator);
}
}
Optimisations ON : (g++ -O2 ..., boring part omitted):
testq %rdi, %rdi
movl %esi, %eax
je .L2
...
.L6:
...
jne .L6 <-- loop
.L2:
rep
ret
This is clearly a loop. But when you disable optimisations, you get:
_Z10sum_helperP4listi:
.LFB6:
...
jne .L2
movl -12(%rbp), %eax
jmp .L3
.L2:
...
call _Z10sum_helperP4listi <-- recursion
.L3:
leave
.cfi_def_cfa 7, 8
ret
Which is recursive.

Help with c++ logic?

Something::methodname()
{
(unsigned char*) ptr = (unsigned char*) m_pptr;
while ((*ptr || *(ptr+1)) && (((unsigned char*)m_pptr+BUFSIZE)<ptr))
ptr++;
if(ptr == m_pptr)
return ptr;
return ptr + 1;
}
m_pptr is a protected member of a class. ptr is local to this function
Could someone help me with the logic of this code? I know it compiles but the answers I'm getting out are not the ones I'm expecting. I am memset-ing a buffer full of A5's and the while loop fails somehow. It skips right past it. Any help would be great.
This will go through a buffer and if the value of the pointer or the value of (ptr+1) is true it will increment the pointer AND the ptr can't exceed the size of the buffer(which is found by m_pptr "pointer to the beginning of the buffer" + buffer size) has to be true also. The if statement says if m_pptr(pointer to beginning of the buffer is the same as ptr then return just the pointer.
this function returns a void* and is passed nothing
(((unsigned char*)m_pptr+BUFSIZE)<ptr))
looks backward:
(((unsigned char*)m_pptr+BUFSIZE)>ptr))
would be more likely; Even more sane:
while (ptr < ((unsigned char*) m_pptr + BUFSIZE)) // until end of buffer
{
if (!*ptr) // null char reached
break;
if (!*(ptr+1)) // null char almost reached
break;
// do stuff
ptr++;
}
This bit looks suspicious to me:
while ((*ptr || *(ptr+1))
Imagine that ptr is pointing to a valid character byte, followed by a NUL terminator byte.
The first sub-test of the above line will evaluate to true, and so ptr gets incremented. Now ptr is pointing at the NUL terminator byte, and *(ptr+1) is pointing at the byte AFTER the NUL terminator byte... which might be garbage/undefined, and therefore might be non-zero, at which point (ptr) will be incremented again (because the second sub-test evaluated to true this time), so that ptr now points to the byte AFTER the NUL terminator byte. And from there on your pointer heads off into la-la-land, trying to interpret data that was never meant to be part of the string it was parsing.
Wouldn't it look cleaner and simpler if you used for-loop instead?
for ( int i =0; i<BUFSIZE && (ptr[i] || ptr[i+1]); i++);
It would be easier to notice wrong comparison, wouldn't it?
And i think it would be also easier to see that in this case it should be
for ( int i =0; i<(BUFSIZE-1) && (ptr[i] || ptr[i+1]); i++);
or even
for ( int i =1; i<BUFSIZE && (ptr[i-1] || ptr[i]); i++);
unless obiviously you accounted for that by having BUFSIZE equal to buffer size minus one.