我在C和Lisp算术计算器中创建一个简单的程序,只涉及整数和"+ - * /"
运算符,我这样做是为了学习目的,这不是我的作业或类似的东西。
所以我已经创建了一个函数来正确地解析它会输出5的这个(+ 2 3)
,所以我知道如何处理非嵌套语句但是当我有类似(+ (* 2 3) (- 4 2))
这样的东西时它会是什么呢好像我可以使用递归来解决这个问题,但我真的不知道怎么做。
我的逻辑遵循(伪代码):`
function parse_line(int n)
get_input(string);
if string[n] == '('
if string[n+1] == operator
if string[n+3] == number
result = parseAllNumbers(); //between ( )
return result;
if string[n+3] == '('
parse_line(n+2);
`
我的逻辑是正确的,如果我有(+ (* 2 3) (- 4 2))
我只会计算。 (* 2 3)
,我将如何计算(- 4 2)
,然后将这两个结果一起添加
答案 0 :(得分:5)
你肯定是在正确的轨道上。
假设我们编写了一个getToken()
函数,它从当前位置读取字符串中的下一个逻辑标记。逻辑令牌可以是数字,'(',')'或四个运算符中的任何一个。然后我们可以递归地计算表达式。
function evaluateExpression(){
var token = getToken();
if( isNumber(token)){
return token;
}else if( isOpenParen(token)){
return evaluateExpression();
}
var numOne = evaluateExpression();
var nextToken = null;
while( !isRightParen(nextToken)){
nextToken = getToken();
numOne = evaluate(token, numOne, nextToken);
}
return numOne;
}
函数isNumber()
和isLeftParen()
执行它们所暗示的内容,如果传递给它的标记分别是数字或左括号,则返回true。 evaluate()
函数接受运算符标记以及两个数字来评估它们。例如,evaluate(+,2,4)
将返回6
而evaluate(-,2,4)
将返回2
。
答案 1 :(得分:2)
这是一个使用递归的解决方案:
#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
答案 2 :(得分:1)
C是最难使用的语言。除非这是家庭作业,否则最好先尝试另一种更高级别的语言。 C缺少字符串以及堆栈等数据结构。正如其他海报建议的那样,这种处理可能更加优雅地递归,但我发现非递归更容易。这是一个部分解决方案,只处理正整数并且缺少一些错误处理:
#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 BAD_LINE 1
#define GOOD_LINE 0
typedef struct
{
unsigned char type;
char operator;
int number;
} token;
int get_tokens(const char *line, token *tokens,int *num_tokens)
{
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 process_expression(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_tokens(token *tokens, int num_tokens)
{
int result = 0;
/* operators "stack" */
char operators[100];
/* "pointer" for current operator */
int operator_index = -1;
/* operands "stack" 1 row for each operator (set of parentheses) */
int operands[100][20];
/* how many operands for current expression? (current operator) */
int expression_operands[100];
for (int i = 0; i < num_tokens; i++)
{
if ( tokens[i].type == OPEN_PAREN )
{
operator_index += 1;
expression_operands[operator_index] = 0;
}
else if ( tokens[i].type == CLOSE_PAREN )
{
result = process_expression(operators[operator_index],
&operands[operator_index][0],
expression_operands[operator_index]);
operator_index -= 1;
if ( operator_index > -1 )
{
operands[operator_index][ expression_operands[operator_index] ] = result;
expression_operands[operator_index] += 1;
}
}
else if ( tokens[i].type == OPERATOR )
{
operators[operator_index] = tokens[i].operator;
}
else if ( tokens[i].type == NUMBER )
{
operands[operator_index][ expression_operands[operator_index] ] = tokens[i].number;
expression_operands[operator_index] += 1;
}
}
return result;
}
void process_lisp_string(const char *string)
{
token tokens[100];
int num_tokens = 0;
int result = get_tokens(string, tokens,&num_tokens);
if ( result == GOOD_LINE )
{
printf("the answer is: %d\n",process_tokens(tokens,num_tokens));
}
else
{
printf("the string contained errors\n");
}
}
int main(const int argc, const char *const argv[])
{
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(line);
process_lisp_string(line2);
process_lisp_string(line3);
process_lisp_string(line4);
}
结果:
the answer is: 54
the answer is: 810
the answer is: 812
the answer is: 38