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;