Page 1 of 2

Really stuck on seperating my buffer into segments

Posted: Fri Jul 04, 2008 10:03 am
by cjhawley001
So i am up to the point where i have everything i need to handle command input from the keyboard.
I have it so when a user presses a key it shows up and i have the ability to put strings or just a char on the screen.

I have been trying to make a simple, very simple calculator. I can add/multiply/subtract/divide digits 0-9...but when i get to double digits that is where i fall...hard...

So i decided to make a buffer to hold all of the keyboard data entered before the enter key is hit.

i have tried this

Code: Select all

while(x < index)
                             {
                                     if(buffer[x] == '+')
                                     {
                                           argument = '+';
                                           x+=1;
                                           flag = x;
                                           
                                     }
                                     if(buffer[x] != '+')
                                     {
                                               if(flag == 0)
                                               {
                                                       data_1[x] = buffer[x];
                                                       x+=1;
                                               }
                                               if(flag != 0)
                                               {
                                                       data_2[x] = buffer[x];
                                                       x+=1;
                                               }  
                                     }
                             }
but that didn't work, i just get the whole buffer printed back to me..

any suggestions?

Re: Really stuck on seperating my buffer into segments

Posted: Fri Jul 04, 2008 10:49 am
by piranha
@Mods: This should be moved to General Programming.

-JL

Re: Really stuck on seperating my buffer into segments

Posted: Fri Jul 04, 2008 1:44 pm
by JamesM

Code: Select all

#include "parser.tab.h"
%%

+   {return PLUS;}
-    {return MINUS;}
/   {return DIVIDE;}
*   {return MULTIPLY;}
0x[0-9]+ {return HEX_NUM;}
[0-9]+ {return DEC_NUM;}
\n  {return NEWLINE;}

Code: Select all

%token PLUS MINUS DIVIDE MULTIPLY HEX_NUM DEC_NUM NEWLINE
%start start
%%

start
  : factor start
  | NEWLINE
  ;

factor
  : term MULTIPLY term
  | term DIVIDE term
  | term
  ;

term
  : number PLUS number
  | number MINUS number
  | number
  ;

number
  : HEX_NUM
  | DEC_NUM
  ;
There you have a flex/bison (lex/yacc) program to recognise arithmetic operations on hex and decimal numbers with correct association.

Google for lex and yacc - they will help you to produce a proper parser, quickly.

cheers,

James

Re: Really stuck on seperating my buffer into segments

Posted: Fri Jul 04, 2008 3:53 pm
by kmcguire
You can also parse complex language semantics by breaking the buffer into tokens. This removes the string manipulation complexity away from your actual expression evaluation code and _can_ make life easier. Take a look at how I break expressions down into layers of tokens.

1. Break the string into tokens.
2. Build depth using parathesis.
3. Solve the structure using a recursive function.

Code: Select all

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>

struct sToken
{
	uint8_t		type;
	uint32_t	value;
	struct sToken	*next;
	struct sToken	*prev;
	struct sToken	*child;
	struct sToken	*parent;
};

uint32_t readnumber(char *buffer, uint32_t i, uint32_t *n)
{
	char 		tmp;
	uint32_t 	x, num;
	for(x = i; x < (strlen(buffer) + 1); ++x)
	{
		if(!((buffer[x] >= '0') && (buffer[x] <= '9')))
		{
			tmp = buffer[x];
			buffer[x] = 0;
			*n = x;
			num =  atoi(&buffer[i]);
			buffer[x] = tmp;
			return num;
		}
	}
	return 0;
}

#define TOKEN_NUMBER 1
#define TOKEN_PLUS 2
#define TOKEN_MINUS 3
#define TOKEN_MULTIPLY 4
#define TOKEN_DIVIDE 5
#define TOKEN_PO 6
#define TOKEN_PC 7
#define TOKEN_SOLVED 8

/*
    Breaks the string into tokens.
*/
#define MAKENEXTTOKEN(x) x->next = (struct sToken*)malloc(sizeof(struct sToken)); memset(x->next, 0, sizeof(struct sToken)); x->next->prev = x; x = x->next
struct sToken* tokenize1(char *buffer)
{
	uint32_t 	x;
	struct sToken	*token, __rtoken;
	memset(&__rtoken, 0, sizeof(__rtoken));
	token = &__rtoken;

	x = 0;
	while(x < strlen(buffer))
	{
		if((buffer[x] >= '0') && (buffer[x] <= '9'))
		{
			MAKENEXTTOKEN(token);
			token->type = TOKEN_NUMBER;
			token->value = readnumber(buffer, x, &x);
			continue;
		}
		switch(buffer[x])
		{
			case '+':
				MAKENEXTTOKEN(token);
				token->type = TOKEN_PLUS;
				break;
			case '-':
				MAKENEXTTOKEN(token);
				token->type = TOKEN_MINUS;
				break;
			case '/':
				MAKENEXTTOKEN(token);
				token->type = TOKEN_DIVIDE;
				break;
			case '*':
				MAKENEXTTOKEN(token);
				token->type = TOKEN_MULTIPLY;
				break;
			case '(':
				MAKENEXTTOKEN(token);
				token->type = TOKEN_PO;
				break;
			case ')':
				MAKENEXTTOKEN(token);
				token->type = TOKEN_PC;
				break;
		}
		++x;
	}
	return __rtoken.next;
}

/*
    Picks up tokens and stacks them into layers.
*/
struct sToken* tokenize2(struct sToken *ftoken)
{
	struct sToken *clayer = 0;
	struct sToken *clayer_last = 0;
	struct sToken *token, *ntoken;

	/* root token */
	clayer = (struct sToken*)malloc(sizeof(struct sToken));
	clayer_last = 0;
	clayer->type = 0;

	token = ftoken;
	while(token != 0)
	{
		if(clayer)
		{
			if(token->type == TOKEN_PC)
			{
				/* backup to parent layer */
				clayer = clayer->parent;
				/* find last token in child chain */
				for(ntoken = clayer->child; ntoken->next != 0; ntoken = ntoken->next);
				clayer_last = ntoken;
				token = token->next;
				continue;
			}
			if(!clayer_last)
			{
				clayer->child = token;
				ntoken = token->next;
				if(token->prev)
				{
					token->prev->next = token->next;
				}
				if(token->next)
				{
					token->next->prev = token->prev;
				}
				token->parent = clayer;
				token->prev = 0;
				token->next = 0;
				clayer_last = token;
			}else{
				clayer_last->next = token;
				ntoken = token->next;
				if(token->prev)
				{
					token->prev->next = token->next;
				}
				if(token->next)
				{
					token->next->prev = token->prev;
				}
				token->parent = clayer;
				token->prev = clayer_last;
				token->prev->next = token;
				token->next = 0;
				clayer_last = token;
			}
			if(token->type == TOKEN_PO)
			{
				token->parent = clayer;
				clayer = token;
				clayer_last = 0;
			}
			token = ntoken;
			continue;
		}
	}
	return ftoken;
}

/*
    Displays the tokens and the layer using spaces on the left.
*/
void display(uint8_t spaces, struct sToken *token)
{
	uint8_t x;
	for(; token != 0; token = token->next)
	{
		for(x = 0; x < spaces; ++x)
		{
			printf(" ");
		}
		printf("this:%x type:%u value:%u next:%x prev:%x parent:%x child:%x\n", token, token->type, token->value, token->next, token->prev, token->parent, token->child);
		if(token->child)
		{
			display(spaces + 2, token->child);
		}
	}
	return;
}

int main(int argc, char *argv[])
{
	char 		*__buffer = "(4 + 5 + 2 + 3 / (3 - 2 + 99232 / 3) + -2";
	char		*buffer;
	struct	sToken	*token;

        /* __buffer is allocated in READ_ONLY memory so we copy it too the heap. */
	buffer = (char*)malloc(strlen(__buffer));
	strcpy(buffer, __buffer);

	token = tokenize1(buffer);
	token = tokenize2(token);
	display(0, token);
	return 1;
}

Re: Really stuck on seperating my buffer into segments

Posted: Sat Jul 05, 2008 4:32 pm
by cjhawley001
alright, thank you all for the advice, and i am going to use all of that information, in fact i have already started with the token idea, and it seems to be getting there, but what was wrong with the code i had?

thank you

chris

Re: Really stuck on seperating my buffer into segments

Posted: Sat Jul 05, 2008 6:59 pm
by kmcguire
I have a hard time determining what your code was supposed to do myself. I mean sometimes I just have trouble wrapping my brain around the simplest things, but at the moment I am unable to understand the code enough. *shrug/unsure*

Re: Really stuck on seperating my buffer into segments

Posted: Sun Jul 06, 2008 1:26 am
by cjhawley001
its just supposed to take the buffer (all keys pressed before enter key is hit) and then add the segments into different blocks, and when buffer[x] == '+' make a flag = 1 and then start adding the chunks to a different block, then i can convert those two blocks into integers and do mathmatical operations and then show the result.

This is a very simple way of making a "calculator" if you can even call it that, i just want to start as small as i can so i dont get into something i cannot finish and then quit....

but yea i just wanted to know why i keep getting the whole buffer in each of my blocks...


thank you!

-chris

Re: Really stuck on seperating my buffer into segments

Posted: Sun Jul 06, 2008 8:08 am
by kmcguire

Code: Select all

if(buffer[x] == '+')
	{
		argument = '+';
		x += 1;
		flag = x;
	}
Well, the first problem I can see is that flags will only equal zero once in the lifetime of the code per call. So:

Code: Select all

		if(flag == 0)
		{
			data_1[x] = buffer[x];
			x+=1;
		}
		if(flag != 0)
		{
			data_2[x] = buffer[x];
			x+=1;
		} 
Is just constantly throwing everything into data_2. Just go through the code by hand and watch x. You will notice that it will only ever be zero once (AND _only_ if the first letter of the main buffer is a '+' symbol), and the remaining time it will always be non-zero which causes it to throw data into data_2.

If you want them to swap between buffers on every occurrence of the addition symbol then:

Code: Select all

if(buffer[x] == '+')
	{
		argument = '+';
		x += 1;
		flag = x&0x1;
	}
That would work great for addition and multiplication because you can perform the operation in any direction (a*b=b*a) (a+b=b+a), but division and multiplication will need to distinguish which buffer was on the left and which was on the right. To do that you could do:

Code: Select all

/* put what was on the left in data_1_num and what was on the right in data_2_num */
data_1_num = ((flag + 1) & 0x1) == 0 ? atoi(&data_1[0]) : atoi(&data_2[0]);
data_2_num = ((flag + 1) & 0x1) == 1 ? atoi(&data_1[0]) : atoi(&data_2[0]);

switch(argument)
{
  case '+':
 .... data_1_num + data_2_num ....
  break;
  case '*':
  .....data_1_num * data_2_num

Re: Really stuck on seperating my buffer into segments

Posted: Sun Jul 06, 2008 11:15 am
by cjhawley001
so would flag = x&0x1 return true or false?

and i do not completely understand the bottom segment of code...could you explain it just a little bit more?

and i really thank you for your help, i think i have wrapped my mind around what i should be doing as opposed to what i was doing.

-chris

Re: Really stuck on seperating my buffer into segments

Posted: Sun Jul 06, 2008 11:47 am
by kmcguire
cjhawley001 wrote:so would flag = x&0x1 return true or false?

and i do not completely understand the bottom segment of code...could you explain it just a little bit more?

and i really thank you for your help, i think i have wrapped my mind around what i should be doing as opposed to what i was doing.

-chris
It would return the value 0x0 or the value 0x1, where 0x0 is evaluated as false and 0x1 as true.

Code: Select all

/* put what was on the left in data_1_num and what was on the right in data_2_num */
data_1_num = ((flag + 1) & 0x1) == 0 ? atoi(&data_1[0]) : atoi(&data_2[0]);
data_2_num = ((flag + 1) & 0x1) == 1 ? atoi(&data_1[0]) : atoi(&data_2[0]);
The equivalent code is:

Code: Select all

if((flag + 1) & 0x1)
{
    data_1_num = atoi(&data_1[0]);
    data_2_num = atoi(&data_2[0];
}else{
    data_1_num = atoi(&data_2[0]);
    data_2_num = atoi(&data_1[0]);
}
http://iupalgo.free.fr/annexes/c_cpp_re ... ional.html <-- For shorthand conditional expressions.

If we just set flag to 0x0 then we know we last filled data_1 with bytes so it was on the right side of the argument, and the opposite is true if flag is 0x1 which means that we just filled data_2 with bytes so it was on the right side.

Also take a look at how you are using the variable x when filling data_1 and data_2. You are essentially starting way beyond the first byte in each buffer. You should use a separate variable to hold the index in each individual buffer (data_1 and data_2). Like:

Code: Select all

if(buffer[x] == '+')
{
  /* do your code and also */
  bindex = 0;
}
Then when filling each buffer use:

Code: Select all

                                             if(flag == 0)
                                               {
                                                       data_1[bindex++] = buffer[x];
                                                       data_1[bindex] = 0;
                                                       x+=1;
                                               }
                                               if(flag != 0)
                                               {
                                                       data_2[bindex++] = buffer[x];
                                                       data_2[bindex] = 0;
                                                       x+=1;
                                               }
So that you start in each buffer at index zero and include a string terminating null for usage with the atoi functions which will convert a ASCII string representing a number into a binary number represented by a integer.

Code: Select all

char *myString = "-2832";
int myNumber = atoi(myString);
printf("String:%s Number:%i\n", myString, myNumber);

Re: Really stuck on seperating my buffer into segments

Posted: Sun Jul 06, 2008 12:19 pm
by cjhawley001

Code: Select all

while(x < idx)
                             {
                                     if(buffer[x] == '+')
                                     {
                                           argument = '+';
                                           x+=1;
                                           flag = x&0x1;
                                           bindex = 0;
                                           
                                     }
                                    if(buffer[x] != '+')
                                     {
                                               if(flag == 0)
                                               {
                                                       data_1[bindex++] = buffer[x];
                                                       data_1[bindex] = 0;
                                                       x+=1;
                                               }
                                              if(flag != 0)
                                               {
                                                       data_2[bindex++] = buffer[x];
                                                      data_2[bindex] = 0;
                                                       x+=1;
                                               }  
                                     }
                             }
that is what i have and all i am getting when i print out data_1 and data_2 is the exact same number, data_1 and data_2 are always the same for some reason, and i cannot figure out why.

and i do understand the rest of the code you have helped me through, it is great, but why are my data_1 and data_2 always the same?

-chris

Re: Really stuck on seperating my buffer into segments

Posted: Sun Jul 06, 2008 12:23 pm
by kmcguire
oops...

Try something like:
flag = (flag+1)&0x1;

That will switch between buffers when separating the buffer by the character '+'.

Re: Really stuck on seperating my buffer into segments

Posted: Sun Jul 06, 2008 12:36 pm
by cjhawley001
doesn't work, i still get the same for each buffer.

why would both of my buffers be the same if i clearly seperate them?!

-chris

Re: Really stuck on seperating my buffer into segments

Posted: Sun Jul 06, 2008 12:45 pm
by kmcguire
The problem could be in how you create them. What is your code for doing that?

Re: Really stuck on seperating my buffer into segments

Posted: Sun Jul 06, 2008 1:47 pm
by cjhawley001
char *data_1;
char *data_2;