So this is my issue, I have to create a program that implements the shunting yard algorithm in C. For this I first need to parse the given mathematical expression into it's component parts. So I figured a simple for loop over a given string would do the trick.
char *math_exp = "2 + 4";
for (int i = 0; (unsigned) i < strlen(math_expr); i++) {
printf("%c", math_expr[i]);
}
> 2 + 4
But this quickly runs into an issue when a string contains a number with more digits than 1.
for (int i = 0; (unsigned) i < strlen(math_expr); i++) {
// skip if char is a space
if ((int) math_expr[i] == 32) {
continue;
}
printf("%c ", math_expr[i]);
}
> 2 2 + 4
The 22 is now treated as two separate numbers. So I tried to loop over all tokens in the string by splitting the string using the delimiter SPACE.
char math_expr[] = "22 + 4";
char *token = strtok(math_expr, " ");
while (token != NULL) {
printf("%s ", token);
token = strtok(NULL, " ");
}
> 22 + 4
This seemed to work but quickly ran into the issue of what to do when there's a bracket in the expression. e.g.:
char math_expr[] = "(22 + 2)";
char *token = strtok(math_expr, " ");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, " ");
}
> (22
> +
> 2)
And now I'm stuck, is there a way to circumvent this issue? I need to be able to extract every operator and number (with all possible digits) furthermore I also need to be able to distinguish brackets from numbers they are attached to. I hoped there was some easy way to do this. Any help is appreaciated.
Tokenization is the first step towards syntactic analysis. As such, it is probably a good idea to encapsulate it into a layer of abstraction, a function that yields one token at a time. This function also discards white space and combines consecutive digits into numbers. It is hard to delegate these steps to strtok(). Finally, the function may rewrap single characters into more structured information.
#include <ctype.h>
#include <stdio.h>
#define T_NUMBER 0
#define T_OPERATOR 1
#define T_BRACKET 2
typedef struct {
int type;
int value;
} token;
/* Reads the next token from stdin. Returns 1 on success, 0 on EOL. */
int next_token(token *t) {
char c;
/* discard spaces silently */
do {
c = getchar();
} while (c == ' ');
if (isdigit(c)) {
t->type = T_NUMBER;
t->value = 0;
do {
t->value = t->value * 10 + (c - '0');
c = getchar();
} while (isdigit(c));
ungetc(c, stdin); /* save the non-digit for next time */
} else if (c == '+' || c == '-' || c == '*' || c == '/') {
t->type = T_OPERATOR;
t->value = c;
} else if (c == '(' || c == ')') {
t->type = T_BRACKET;
t->value = c;
} else if (c == '\n') {
ungetc(c, stdin); /* make sure we always return 0 from now on */
return 0;
} else {
/* handle illegal character */
}
return 1;
}
int main() {
token t;
while (next_token(&t)) {
switch (t.type) {
case T_NUMBER: printf("number %d\n", t.value); break;
case T_OPERATOR: printf("operator %c\n", t.value); break;
case T_BRACKET: printf("bracket %c\n", t.value); break;
}
}
return 0;
}
Sample run:
(22+ 37 * ( 1534-9)) + 18
bracket (
number 22
operator +
number 37
operator *
bracket (
number 1534
operator -
number 9
bracket )
bracket )
operator +
number 18
Related
I have the following input:
1 (2 ,3 ,4) lantern
The number of int inputs between the parenthesis is unknown, and could extend for a while.
My original thought was to scanf() the first int, then create a while loop to determine when the closed paranethsis is scanned. Then finally use fgets() to get the string at the end, something similar to this.
scanf("%d", &address); //first input
scanf("%c", &paren); //scan the '(' or ',' or ')'
int current_room = 0; //index for array inside parenthsis
while(paren == '(' || paren == ','){
scanf("%d,", adjoined_room[current_room]); //scan am int
scanf("%c", &paren); //scan a ',' or ')'
current_room++; //increase the index
}
This however prints the following output when I print my address, array, and string:
Address: 1
Item: (2 ,3 ,4) lantern
The inputted ints between the parenthesis were never set to the array. Is there a better way to determine when ')' is inputted?
The problem is that scanf("%c", will read the very next character in the input, without skipping any whitespace. If you want to skip whitespace, you need a space in the format, eg scanf(" %c",. You should also check the scanf return value to make sure that you got an integer
Adding that to your code gives you something like:
if (scanf("%d", &address) != 1) { //first input
fprintf(stderr, "syntax error\n");
return; // not an integer -- do something else
}
scanf(" %c", &paren); //scan the '(' or ',' or ')'
int current_room = 0; //index for array inside parenthsis
while(paren == '(' || paren == ','){
if (scanf("%d", adjoined_room[current_room]) == 1) { //scan an int
current_room++; //increase the index
}
scanf(" %c", &paren); //scan a ',' or ')'
if (paren != ',' && paren != ')') {
fprintf(stderr, "syntax error\m");
return;
}
}
If you want to do this with interactive input, you should probably use fgets or getline to read entire lines and sscanf to parse each line independently so you don't confuse your user when there's an error in the middle of a line. The "read line + sscanf" is also very useful if you have a number of different patterns that you want to try (sscanf on the same line with different formats to find the first one that matches).
scanf should never be used. Ever. But....you might try something like:
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
void * xrealloc(void *buf, size_t num, size_t siz);
int
main(void)
{
size_t cap = 4;
char buf[1024];
int *x = xrealloc(NULL, cap, sizeof *x);
if( scanf("%d ( %d", x, x + 1) != 2 ){
errx(EXIT_FAILURE, "Ivalid input");
}
int *y = x + 2;
while( scanf(",%d", y) == 1 ){
if( ++y == x + cap ){
cap += 4;
x = xrealloc(x, cap, sizeof *x);
}
}
if( scanf(")%1023s", buf) != 1 ){
errx(EXIT_FAILURE, "Ivalid input");
}
for( unsigned i = 0; i < y - x; i += 1 ){
printf("x[%d] = %d\n", i, x[i]);
}
printf("%s\n", buf);
return 0;
}
void *
xrealloc(void *buf, size_t num, size_t siz)
{
char *b = buf;
b = realloc(b, num * siz);
if( b == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
return b;
}
This does not correctly handle input with a trailing comma like: 1 (2 ,3 ,4, ) lantern, and I'm sure there are many other inputs that it does not like. Exercise left for the reader.
You probably don't want to use an initial capacity as small as 4, but it's convenient for simple testing.
This may not be the most popular answer, and it may or may not help your immediate goals, but I am of the philosophy to read input as a stream of bytes and parse via (crude or sophisticated) state machine:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define process_word(x) (printf("Got string \'%s\'\n", x))
#define process_number(x) (printf("Got number %lu\n", strtoul(x, NULL, 10)))
int main(void) {
int c;
int depth = 0;
size_t i;
char digitbuffer[256];
char alphabuffer[256];
while ((c = fgetc(stdin)) != EOF) {
switch (c) {
case ' ':
case ',':
break;
case '(':
depth++;
break;
case ')':
if (depth == 0) perror("Mismatched parenthesis, skipping");
else depth--;
break;
default:
if (isalpha(c)) {
memset(alphabuffer, 0, 256);
alphabuffer[0] = c;
i = 1;
while ((c = fgetc(stdin)) != EOF &&
isalpha(c) &&
i < 255) {
alphabuffer[i++] = c;
}
if (!isalpha(c) && c != EOF) ungetc(c, stdin);
process_word(alphabuffer);
}
else if (isdigit(c)) {
memset(digitbuffer, 0, 256);
digitbuffer[0] = c;
i = 1;
while ((c = fgetc(stdin)) != EOF &&
isdigit(c) &&
i < 255) {
digitbuffer[i++] = c;
}
if (!isdigit(c) && c != EOF) ungetc(c, stdin);
process_number(digitbuffer);
}
break;
}
}
return 0;
}
This gives you the most control over handling your specific data format, in my opinion.
You can define your own process_word() and process_number() functions, of course. process_number() might assign the number to the address field of a record if depth == 0, for example, or add it to adjacent_room[] if depth == 1. process_word() might add the string to the item field of the same record. Completely up to you. ¯\_(ツ)_/¯
this program checks weather the entered string is palindrome or not . it should be in a way like it should even tell the string is palindrome if there is space or any special character
like messi is a palindrome of iss em
and ronald!o is a palindrome of odlanor
this is the program and for some odd reason it is strucking and not working
#include <stdio.h>
#include <string.h>
int main() {
char palstr[100], ans[100];
printf("enter the string for checking weather the string is a palindrome or not");
scanf("%[^/n]", &palstr);
int ispalin = 1, i = 0, n = 0;
int num = strlen(palstr);
printf("the total length of the string is %d", num);
while (i <= num) {
if (palstr[i] == ' ' || palstr[i] == ',' || palstr[i] == '.' ||
palstr[i] == '!' || palstr[i] == '?') {
i++;
}
palstr[n++] == palstr[i++];
}
int j = num;
i = 0;
while (i <= num) {
ans[j--] = palstr[i];
}
printf("the reverse of the string %s is %s", palstr, ans);
if (ans == palstr)
printf("the string is a palindrome");
else
printf("the string is not a palindrome");
return 0;
}
A few points to consider. First, regarding the code:
if (ans == palstr)
This is not how you compare strings in C, it compares the addresses of the strings, which are always different in this case.
The correct way to compare strings is:
if (strcmp(ans, palstr) == 0)
Second, you should work out the length of the string after you have removed all unwanted characters since that's the length you'll be working with. By that I mean something like:
char *src = palstr, dst = palstr;
while (*src != '\0') {
if (*c != ' ' && *src != ',' && *src != '.' && *src != '!' && *src != '?') {
*dst++ = *src;
}
src++;
}
Third, you have a bug in your while loop anyway in that, if you get two consecutive bad characters, you will only remove the first (since your if does that then blindly copies the next character regardless).
Fourth, you may want to consider just stripping out all non-alpha characters rather than that small selection:
#include <ctype.h>
if (! isalpha(*src) {
*dst++ = *src;
}
Fifth and finally, you don't really need to create a new string to check for a palindrome (though you may still need to if you want to print the string in reverse), you can just start at both ends and move inward, something like:
char *left = &palstr, right = palstr + strlen(palstr) - 1, ispalin = 1;
while (left < right) {
if (*left++ != *right--) {
ispalin = 0;
break;
}
}
There may be other things I've missed but that should be enough to start on.
well, the are so many bugs in this code. I will point them out with comments.
#include <stdio.h>
#include <string.h>
int main() {
char palstr[100], ans[100];
printf("enter the string for checking weather the string is a palindrome or not\n");
scanf("%s", palstr); // your former code won't stop input util Ctrl+D
int ispalin = 1, i = 0, n = 0;
int num = strlen(palstr);
printf("the total length of the string is %d\n", num);
while (i < num) { // < insted of <=
if (palstr[i] == ' ' || palstr[i] == ',' || palstr[i] == '.' ||
palstr[i] == '!' || palstr[i] == '?') {
i++;
continue;// without this, marks still in the string
}
palstr[n++] = palstr[i++]; //should be =
}
palstr[n] = '\0'; //
num = n; // the length might be changed
i = 0;
int j = num-1; // reverse
while (i < num) { //
ans[i++] = palstr[j--]; //
}
ans[i] = '\0'; //
printf("the reverse of the string %s is %s\n", palstr, ans);
//if (ans == palstr) they can never be equal
if (strcmp(ans, palstr)==0)
printf("the string is a palindrome\n");
else
printf("the string is not a palindrome\n");
return 0;
}
What I'm trying to obtain is a calculator that will take infix notation, ignore insignificant whitespace characters like " " or '#', then convert that infix notaion into postfix notation and do simple calculations like addition, subtraction etc. So far the code is taking input in infix notation trimming it in a way that ignores insignificant whitespace characters and outputs the postfix notation.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>;
#include <ctype.h>;
#define MAX_LENGTH 100
//Functions
void push(char x);
char pop();
void trimString(char string[], char newString[]);
void inputToRPN(char trimmedExp[], char rpnExp[]);
int calculateRPN(char rpnExp[]);
char stack[MAX_LENGTH];
char resStack[MAX_LENGTH];
int top = -1;
int resTop = -1;
int index = 0;
int main() {
int res;
char exp[MAX_LENGTH] = "10 +2";
char trimmedExpression[MAX_LENGTH];
char rpnExpression[MAX_LENGTH];
// Input commented out as per suggestion in comments
//printf("Enter expression : ");
//fgets(exp, 100, stdin);
printf("Infix expression: %s \n", exp);
trimString(exp, trimmedExpression);
printf("\n");
inputToRPN(trimmedExpression, rpnExpression);
res = calculateRPN(rpnExpression);
//printf("Result of calculation: %d", res);
return 0;
}
void push(char x) {
stack[++top] = x;
}
char pop() {
if (top == -1)
return -1;
else
return stack[top--];
}
int priority(char x) {
if (x == '(')
return 0;
if (x == '+' || x == '-')
return 1;
if (x == '*' || x == '/')
return 2;
return 0;
}
void trimString(char string[], char newString[]) {
int i = 0, j = 0;
while (string[i] != '\0' && string[i] != 10) {
// Range of significant characters
if (string[i] >= '(' && string[i] <= '9') {
newString[j] = string[i];
i++, j++;
}
else {
i++;
}
}
newString[j] = 0;
}
void inputToRPN(char trimmedExp[], char rpnExp[]) {
char* e, x;
e = trimmedExp;
while (*e != '\0') {
// Add to RPN if character is alphanumeric
if (isalnum(*e)) {
rpnExp[index] = *e;
index++;
}
// Add to stack if is an open brace
else if (*e == '(')
push(*e);
// Add all operators to the expression until finding open braces
else if (*e == ')') {
while ((x = pop()) != '(') {
rpnExp[index] = x;
index++;
}
}
// If none of the above, that is an operator - check it's priority.
// If it's priority is less that that of the one on top of the stack add the operator from the top of the stack to the expression; untill it's priority is higher.
// At the end add current operator to the stack.
else {
while (priority(stack[top]) >= priority(*e)) {
rpnExp[index] = pop();
index++;
}
push(*e);
}
e++;
}
while (top != -1) {
rpnExp[index] = pop();
index++;
}
// Terminating character at the end of the string
rpnExp[index] = 0;
}
void pushRes(char x) {
printf("pushing: %c \n", x);
resStack[++resTop] = x;
}
char popRes() {
printf("poping \n");
if (resTop == -1)
return -1;
else
return resStack[resTop--];
}
int isValidOperator(char c) {
if (c == '/' || c == '*' || c == '+' || c == '-')
return 1;
else
return 0;
}
int calculateRPN(char rpnExp[]) {
// Doesnt do anything yet, just prints out the compiled reverse polish notation
char* c;
int result = 0;
c = rpnExp;
printf("Postfix expression: %s", rpnExp);
return result;
}
The problem I've stumbled upon is when the infix input has multiple digits say 10+2 the code will treat each digit individually. Therefore the whole expression will be invalid when calculating result. I'm almost certain the issue lies in this line of code:
// Add to RPN if character is alphanumeric
if (isalnum(*e)) {
rpnExp[index] = *e;
index++;
}
Despite that I've got no idea how should i treat multiple digits while adding them to the expression, since the input is in form of character and there can be N amount of digits that have coresponding ascii values which range from 0-9. Looking forward to your answears.
Edit: made it so the code compiles and the input is hard coded.
Okay, so thanks to Bodos suggestions I've fixed the issue. Adding one while loop in this section:
if (isalnum(*e)) {
rpnExp[index] = *e;
index++;
}
enabled me to add one character after every number (including the N digit ones).
Thanks to which I was later able to perform calculations in calculateRPN function that would eventually lead to correct answear.
The issue has been resolved.
I am stuck on this problem:
A user writes a math expression and the program need to extract from it all subexpressions that are inside ( ) ex. (x+2) or (x+(y-2)).
For example, if the user enters 2-(5+(x-6)-(y+9)), the program should return (x-6), (y+9), (5+(x-6)-(y+9))
This is what I've tried to do.
#include<stdio.h>
int main()
{
char a[100];
int i=0,t,j=0;
printf("enter math expression:\n");
while( (a[i++]=getchar()) != '\n' && i < 100);
a[i] = '\0';
for (i=0; a[i]!='\0'; i++)
{
if (a[i]=='(')
{ printf("found (\n");
j++;
while (a[i] !=')')
printf("%c",a[i++]);
printf("%c",a[i]);
Since you are dealing with nested expressions, you need to keep a stack around in order to match parentheses. Ideally inside the loop you should:
Whenever found a '(', push position within the string into the stack
When a ')' is found, then pop from the stack the position of the matching '('. You have start-end indexes for your expression.
Continue until string is finished
Example (x + (y+2)):
i == 0 -> '(' -> s.push(0);
i == 1 -> 'x'
i == 2 -> '+'
i == 3 -> '(' -> s.push(3);
i == 4 -> 'y'
i == 5 -> '+'
i == 6 -> '2'
i == 7 -> ')' -> s.pop() [3, 7] contains '(y + 2)'
i == 8 -> ')' -> s.pop() [0, 8] contains '(x + (y+2))'
Let, s be a cstring in this context.
Since in valid mathematical expression parenthesis are balanced, we can observe that,
s+1 is balanced if s[0] is not '('
if s[0] is '(' then we are at the start of a parenthesis'ed expression.
At the case of #1 we do not care about the first character. So, we can set s = s+1 and start over again.
At the case of #2 we have to find the matched end for the first character. So, we divide it in two part. The matched expression and the tail. Both are valid expression. So, we start with them over again.
int main()
{
char s[] = "2-(5+(x-6)-(y+9))";// s have to be modifiable.
extractAndPrint(s, 0); // we are at start and 0 indicates balanced
return 0;
}
Now,
void extractAndPrint(char *s, int found)
{
if(s[0] == 0) return;//no more honey
if(!found){ //so far balanced
if(s[0] == '(') extractAndPrint(s+1, 1);// case 2
else extractAndPrint(s+1, 0); //this is the case 1
} else {//start of a expression
char *t;
//separates the end of current expression
//and the remaining part.
mark_end(s, 0, &t);
printf("(%s)\n", s);
extractAndPrint(s, 0);//potentially contain more expression
extractAndPrint(t, 0);//check past the previous exp
}
}
I liked recursion here too. It takes less thinking for me. Can be implemented in more elegant way.
void mark_end(char *s, int c, char **t)
{
if(c == 0){
if(s[0] == ')'){
*t = s+1;
*s = '\0';
} else if(s[0] == '('){
mark_end(s+1, c+1, t);
} else {
mark_end(s+1, c, t);
}
} else {
if(s[0] == ')'){
mark_end(s+1, c-1, t);
} else if(s[0] == '('){
mark_end(s+1, c+1, t);
} else {
mark_end(s+1, c, t);
}
}
}
OUTPUT:
(5+(x-6)-(y+9))
(x-6)
(y+9)
I recommend you to use state machine, in your case this state machine should be suitable :
so your main will be a kind of a switch case, take care of writing your pop and push fuctions and represent your heap with a good structure
You should use recursion to parse the string as a tree of parenthesis. Here is an example showing how to do it :
#include <stdio.h>
#include <string.h>
#define MAX_DATA 100
int mathexp(const char *exp, int start, int end)
{
int i = start;
while(i < (start + end) && exp[i] != ')') {
if(exp[i] == '(') {
i = mathexp(exp, i + 1, end) + 1;
} else {
i++;
}
}
char subexp[i - start];
memcpy(subexp, &exp[start], i - start);
subexp[i - start] = '\0';
printf("%s\n", subexp);
return i;
}
int main(int argc, char *argv[])
{
char input[MAX_DATA];
printf("Enter a math expression: ");
fgets(input, sizeof(input), stdin);
input[strcspn(input, "\r\n")] = '\0'; // remove trailing \r\n
mathexp(input, 0, strlen(input));
return 0;
}
and when you test it, you have :
Enter a math expression: 2-(5+(x-6)-(y+9))
x-6
y+9
5+(x-6)-(y+9)
2-(5+(x-6)-(y+9))
I want to create an array in which i can store run time supplied input such as - + 2 * 3 4 / 12 6 (total 9 elements here). Suppose none of input instances require more than 50 indices in array. I'm thinking of an integer array for this purpose but i'm not getting any format specifier which can be used in scanf() for taking input (terminated at return/Enter keypress ) so that i can distinguish latter in the program whether particular index was a char or int and what was its value.
If i use %c or even getchar() function I'm facing trouble to handle integers more than one digit.
if i use %d chars such as * + - / are not getting stored. so on and so forth.
So kindly suggest some way to do it if it is feasible.
When I learned programming (long time ago ...) my teacher said "never begin to code until it is clear what you want to achieve with a correct analysis". If I correctly understood, you are building a calculator, with only five operators (+-/*%) that follows following grammar :
expr : number
| operator expr expr
with the following lexical tokens :
operator: single character among +-*/%
number: consecutive sequence of decimal digits ([0-9]*)
not printing characters (space, tab, \r, \n) are used as delimiters or otherwise ignored
any other character causes an error.
Ok : that's your current specs, if you later want to use decimal numbers you just have to change the number definition to allow one optional decimal point.
Written like that, it would be easy to use lex and yacc, but for such a simple grammar, it is certainly overkill.
Even if we defined spaces as separator, it is not possible to use scanf to get tokens, because it would silently eat + signs : +12 is same as 12.
So you must build a simple lexer using getc that returns tokens, and then a parser that recursively compute expressions. No need for storing anything in arrays :
typedef struct _token {
enum {OPERATOR, INT, END, ERROR } type;
union {
int ival;
char op;
} value;
} TOKEN;
TOKEN getToken(FILE *fdin) {
static const char valid_op[] = "+-*/%";
static const char spaces[] = " \t\r\n";
int c;
TOKEN tok;
int val = 0;
int isval = 0;
while ((c = getc(fdin)) != EOF) {
if ((c >= '0') && (c <= '9')) {
val = 10 * val + (c - '0');
isval = 1;
}
else if (isval != 0) {
tok.type = INT;
tok.value.ival = val;
ungetc(c, fdin);
return tok;
}
else if (strchr(valid_op, c)) {
tok.type = OPERATOR;
tok.value.op = c;
return tok;
}
else if (! strchr(spaces, c)) {
tok.type = ERROR;
return tok;
}
}
tok.type = END;
return tok;
}
int parse(FILE *fdin, int *typ) {
int i, j;
*typ = INT;
for(;;) {
TOKEN tok = getToken(fdin);
if (tok.type == INT) {
return tok.value.ival;
}
else if (tok.type == OPERATOR) {
i = parse(fdin, typ);
if (*typ != INT) {
*typ = ERROR;
return 0;
}
j = parse(fdin, typ);
if (*typ != INT) {
*typ = ERROR;
return 0;
}
switch(tok.value.op) {
case '+': return i+j;
case '-': return i-j;
case '*': return i*j;
case '/': return i/j;
case '%': return i * j / 100;
}
}
else {
*typ = tok.type;
return 0;
}
}
}
You need a data type that can hold various types of data: operators and integers, maybe even floating-point numbers or names (of variables or functions).
A common approach in C is to use a union, which can hold several types in the same space. You can only use one of these types at a time, so you need a way to indicate which of the types is active, which can be done with an enum. Then wrap the enum and the union in a struct to have them tidily alongside each other.
Below is an example implementation of auch a data type. It doesn't do any operations, it only parses a string and prints the tokens.
As in your example, all tokens must be separated by white space, so that strtok can find them. If you want to recognize 5/2 as three tokens, you can build a lexer as Serge Ballesta suggested in his very systematic answer. The implementation below doesn't recognize negative numbers such as -1. Error handling is also very basic.
This code might still serve you as starting point for a solution:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
enum Type { /* enumeration of possible types */
Operator,
Integer,
Float,
Name,
Illegal
};
struct Token {
enum Type type; /* token type */
union { /* mutually exclusive data fields */
long long int l; /* ... for Integer */
double x; /* ... for Float */
char name[20]; /* ... for Name and Operator */
} data;
};
struct Token illegal(const char *str)
{
struct Token tk = {Illegal};
snprintf(tk.data.name, 20, "%s", str);
return tk;
}
struct Token parse(const char *str)
{
struct Token tk = {Illegal};
if (strchr("+-*/%", *str)) {
if (str[1]) return illegal("Overlong operator");
tk.type = Operator;
strcpy(tk.data.name, str);
return tk;
}
if (isdigit(*str)) {
double x;
long long l;
char *end;
l = strtoll(str, &end, 0);
if (end != str && *end == '\0') {
tk.type = Integer;
tk.data.l = l;
return tk;
}
x = strtod(str, &end);
if (end != str && *end == '\0') {
tk.type = Float;
tk.data.x = x;
return tk;
}
return illegal("Illegal number");
}
if (isalpha(*str)) {
const char *p = str;
while (*p) {
if (!isalnum(*p++)) return illegal("Illegal name");
}
tk.type = Name;
snprintf(tk.data.name, 20, "%s", str);
return tk;
}
return illegal("Illegal character");
}
int split(struct Token tk[], int max, char *str)
{
int n = 0;
char *p;
p = strtok(str, " \t\n");
while (p) {
struct Token curr = parse(p);
if (curr.type == Illegal) {
fprintf(stderr, "Parse error: %s.\n", curr.data.name);
return -1;
}
if (n < max) tk[n] = curr;
n++;
p = strtok(NULL, " \t\n");
}
return n;
}
void print(struct Token tk)
{
switch (tk.type) {
case Operator: printf("operator %c\n", tk.data.name[0]);
break;
case Integer: printf("integer %lld\n", tk.data.l);
break;
case Float: printf("float %g\n", tk.data.x);
break;
case Name: printf("name \"%s\"\n", tk.data.name);
break;
default: printf("illegal token\n");
}
}
int main()
{
char line[] = "- + 2 * alpha beta / 12.0 6";
struct Token tk[20];
int i, n;
n = split(tk, 20, line);
for (i = 0; i < n; i++) {
print(tk[i]);
}
return 0;
}
Use
fgets() to read till end of line.
Parse the line and break the line into tokens using strtok() with space as delimiter.
Check whether each token is char or digit. There are multiple ways to check whether the token is digit or not. Use strtol() to convert tokens to integers this will help you to find difference between 0 and character also