再帰を使用するソリューションは次のとおりです。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define OPERATOR 0
#define OPEN_PAREN 1
#define CLOSE_PAREN 2
#define NUMBER 3
#define END_OF_EXPR 4
#define BAD_LINE 1
#define GOOD_LINE 0
typedef struct
{
unsigned char type;
char operator;
int number;
} token;
token tokens[100];
int num_tokens = 0;
int token_counter = 0;
token get_token(void)
{
token temp;
if ( token_counter < num_tokens )
{
temp = tokens[token_counter];
token_counter += 1;
}
else
{
temp.type = END_OF_EXPR;
}
return temp;
}
int tokenize(const char *line, token *tokens,int *num_tokens)
{
token_counter = 0;
int number_digit = 0;
token aToken;
int length = strlen(line);
char number_array[20];
*num_tokens = 0;
int num_open_paren = 0;
int num_close_paren = 0;
for (int i = 0; i < length; i++)
{
/* ignore whitespace */
if ( line[i] == ' ' || line[i] == '\t' || line[i] == '\n' || line[i] == '\r' )
{
if ( number_digit > 0 )
{
number_array[number_digit] = '\0';
aToken.number = atoi(number_array);
aToken.type = NUMBER;
tokens[*num_tokens] = aToken;
*num_tokens += 1;
number_digit = 0;
}
}
else if ( line[i] == '(')
{
aToken.type = OPEN_PAREN;
tokens[*num_tokens] = aToken;
*num_tokens += 1;
num_open_paren += 1;
}
else if (line[i] == ')' )
{
if ( number_digit > 0 )
{
number_array[number_digit] = '\0';
aToken.number = atoi(number_array);
aToken.type = NUMBER;
tokens[*num_tokens] = aToken;
*num_tokens += 1;
number_digit = 0;
}
aToken.type = CLOSE_PAREN;
tokens[*num_tokens] = aToken;
*num_tokens += 1;
num_close_paren += 1;
}
else if ( line[i] == '*' || line[i] == '+' ||
line[i] == '/' || line[i] == '-' )
{
aToken.type = OPERATOR;
aToken.operator = line[i];
tokens[*num_tokens] = aToken;
*num_tokens += 1;
}
else if ( isdigit(line[i]) )
{
number_array[number_digit] = line[i];
number_digit += 1;
}
else
{
printf("%c - the %d character - is illegal\n",line[i],i+1);
return BAD_LINE;
}
}
if ( num_open_paren == num_close_paren )
{
return GOOD_LINE;
}
else
{
printf("mismatched parentheses\n:%s\n",line);
return BAD_LINE;
}
}
int evaluate(char operator, int *operands, int num_operands)
{
int result = 0;
switch (operator)
{
case '+':
for (int i = 0; i < num_operands; i++)
{
result += operands[i];
}
break;
case '-':
result = operands[0];
for (int i = 1; i < num_operands; i++)
{
result -= operands[i];
}
break;
case '*':
result = operands[0];
for (int i = 1; i < num_operands; i++)
{
result *= operands[i];
}
break;
case '/':
result = operands[0];
for (int i = 1; i < num_operands; i++)
{
result /= operands[i];
}
break;
default:
printf("ERROR invalid operator: %c\n",operator);
}
return result;
}
int process_expression(void)
{
int result = 0;
token current_token = get_token();
if ( current_token.type != OPERATOR )
{
fprintf(stderr,"ERROR: %s expecting operator\n",__func__);
exit(1);
}
char operator = current_token.operator;
current_token = get_token();
int operands[200];
int operands_index = 0;
while ( current_token.type != CLOSE_PAREN && current_token.type != END_OF_EXPR)
{
if ( current_token.type == NUMBER )
{
operands[operands_index] = current_token.number;
operands_index += 1;
}
else if ( current_token.type == OPEN_PAREN )
{
operands[operands_index] = process_expression();
operands_index += 1;
}
current_token = get_token();
}
result = evaluate(operator,operands,operands_index);
return result;
}
void process_lisp_string(const char *line)
{
int result = tokenize(line, tokens,&num_tokens);
if ( result == GOOD_LINE )
{
token first = get_token();
if ( first.type == OPEN_PAREN )
printf("the answer for %s is: %d\n",line, process_expression());
else
{
fprintf(stderr,"ERROR: no open parentheses at front of expression\n");
fprintf(stderr,"token type:%d\n",first.type);
}
}
else
{
printf("the line contained errors\n");
}
}
int main(const int argc, const char *const argv[])
{
char *test = "(+ 2 2 )";
char *line = "(+ (+ 30 20) 2 2)";
char *line2 = "(- (+ 1000 10) 200)";
char *line3 = "(- (+ 1000 10) (- 200 10) (* 2 4))";
char *line4 = "(+ (+ 10 10) (* 2 4) (* 2 3) (* 2 (- 3 1)))";
process_lisp_string(test);
process_lisp_string(line);
process_lisp_string(line2);
process_lisp_string(line3);
process_lisp_string(line4);
}
出力:
the answer for (+ 2 2 ) is: 4
the answer for (+ (+ 30 20) 2 2) is: 54
the answer for (- (+ 1000 10) 200) is: 810
the answer for (- (+ 1000 10) (- 200 10) (* 2 4)) is: 812
the answer for (+ (+ 10 10) (* 2 4) (* 2 3) (* 2 (- 3 1))) is: 38