123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- /* $Id$
- * MegaZeux
- *
- * Copyright (C) 1996 Greg Janson
- * Copyright (C) 1998 Matthew D. Williams - dbwilli@scsn.net
- * Copyright (C) 2002 Gilead Kutnick - exophase@adelphia.net
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #include "expr.h"
- #include "string.h"
- #include "counter.h"
- #include "runrobot.h"
- #include <ctype.h>
- #include <stdlib.h>
- long int last_val;
- long int parse_expression(char far **expression, int &error, int id)
- {
- long int operand_val;
- int current_arg;
- long int c_operator;
- long int value;
- error = 0;
- // Skip initial whitespace..
- skip_whitespace(expression);
- value = parse_argument(expression, current_arg, id);
- if((current_arg != 0) && (current_arg != 2))
- {
- // First argument must be a value type.
- error = 1;
- return(-99);
- }
- skip_whitespace(expression);
- while(1)
- {
- if(**expression == ')')
- {
- // Close paren, safe to go.
- break;
- }
- c_operator = parse_argument(expression, current_arg, id);
- // Next arg must be an operator, unless it's a negative number,
- // in which case it's considered + num
- if(current_arg == 2)
- {
- value = evaluate_operation(value, 1, c_operator);
- }
- else
- {
- if(current_arg != 1)
- {
- error = 2;
- return(-100);
- }
- skip_whitespace(expression);
- operand_val = parse_argument(expression, current_arg, id);
- // And now it must be an integer.
- if((current_arg != 0) && (current_arg != 2))
- {
- error = 3;
- return(-102);
- }
- // Evaluate it.
- value = evaluate_operation(value, c_operator, operand_val);
- }
- skip_whitespace(expression);
- }
-
- last_val = value;
- return(value);
- }
- long int parse_argument(char far **argument, int &type, int id)
- {
- int first_char = **argument;
- // Test the first one.
-
- switch(first_char)
- {
- // Addition operator
- case '+':
- {
- type = 1;
- (*argument)++;
- return(1);
- }
- // Subtraction operator
- case '-':
- {
- (*argument)++;
- if(!isspace(**argument))
- {
- int t2;
- long int val = parse_argument(argument, t2, id);
- if((t2 == 0) || (t2 == 2))
- {
- val = -val;
- type = 2;
- return(val);
- }
- else
- {
- type = -1;
- return(-1);
- }
- }
- type = 1;
- return(2);
- }
- // Multiplication operator
- case '*':
- {
- type = 1;
- (*argument)++;
- return(3);
- }
- // Division operator
- case '/':
- {
- type = 1;
- (*argument)++;
- return(4);
- }
- // Modulus operator
- case '%':
- {
- type = 1;
- (*argument)++;
- return(5);
- }
- // Exponent operator
- case '^':
- {
- type = 1;
- (*argument)++;
- return(6);
- }
- // Bitwise AND operator
- case 'a':
- {
- type = 1;
- (*argument)++;
- return(7);
- }
-
- // Bitwise OR operator
- case 'o':
- {
- type = 1;
- (*argument)++;
- return(8);
- }
- // Bitwise XOR operator
- case 'x':
- {
- type = 1;
- (*argument)++;
- return(9);
- }
- // Less than/bitshift left
- case '<':
- {
- type = 1;
- (*argument)++;
- if(**argument == '<')
- {
- (*argument)++;
- return(10);
- }
- if(**argument == '=')
- {
- (*argument)++;
- return(14);
- }
- return(13);
- }
- // Greater than/bitshift right
- case '>':
- {
- type = 1;
- (*argument)++;
- if(**argument == '>')
- {
- (*argument)++;
- return(11);
- }
- if(**argument == '=')
- {
- (*argument)++;
- return(16);
- }
- return(15);
- }
- // Equality
- case '=':
- {
- type = 1;
- (*argument)++;
- return(12);
- }
- // Logical negation
- case '!':
- {
- type = 1;
- if(*(*argument + 1) == '=')
- {
- (*argument) += 2;
- return(17);
- }
- }
- // One's complement
- case '~':
- {
- (*argument)++;
- if(!isspace(**argument))
- {
- int t2;
- long int val = parse_argument(argument, t2, id);
- if((t2 == 0) || (t2 == 2))
- {
- val = ~val;
- type = 2;
- return(val);
- }
- else
- {
- type = -1;
- return(-1);
- }
- }
- }
- // # is the last expression value, 32bit.
- case '#':
- {
- type = 0;
- (*argument)++;
- return(last_val);
- }
- // The evil null terminator...
- case '\0':
- {
- type = -1;
- return(-1);
- }
- // Parentheses! Recursive goodness...
- // Treat a valid return as an argument.
- case '(':
- {
- int error;
- long int val;
- char far *a_ptr = (*argument) + 1;
- val = parse_expression(&a_ptr, error, id);
- if(error)
- {
- type = -1;
- return(-1);
- }
- else
- {
- *argument = a_ptr + 1;
- type = 0;
- return(val);
- }
- }
-
- // Begins with a ' or a & makes it a message ('counter')
- case '&':
- case '\'':
- {
- // Find where the next ' or & is
- char t_char = first_char;
- (*argument)++;
- int count = 0;
- char temp[80];
- char temp2[80];
- // Remember, null terminator is evil; if it's hit exit completely.
- while(((**argument) != t_char) && (count < 80))
- {
- // If a nested expression is hit closing 's should be ignored
- if((**argument) == '(')
- {
- int close_paren_count = 1;
- // The number of )'s to expect.. finding one decreases it..
- // And finding a ( increases it.
- while((close_paren_count) && (count < 80))
- {
- temp[count] = **argument;
- (*argument)++;
- count++;
- switch(**argument)
- {
- case '\0':
- {
- type = -1;
- return(-1);
- }
- case ')':
- {
- close_paren_count--;
- break;
- }
- case '(':
- {
- close_paren_count++;
- break;
- }
- }
- }
- }
- else
- {
- if(**argument == '\0')
- {
- type = -1;
- return(-1);
- }
- temp[count] = **argument;
- (*argument)++;
- count++;
- }
- }
- type = 0;
- (*argument)++;
- temp[count] = '\0';
- tr_msg(temp, id, temp2);
- return((long int)get_counter(temp2, id));
- }
- // Otherwise, it must be an integer, or just something invalid.
- default:
- {
- if((first_char >= '0') && (first_char <= '9'))
- {
- // It's good.
- char *end_p;
- long int val = strtol(*argument, &end_p, 0);
- *argument = end_p;
- type = 0;
- return(val);
- }
- else
- {
- // It's not so good..
- type = -1;
- return(-1);
- }
- }
- }
- }
- void skip_whitespace(char **expression)
- {
- while(isspace(**expression))
- {
- (*expression)++;
- }
- }
- long int evaluate_operation(long int operand_a, int c_operator,
- long int operand_b)
- {
- switch(c_operator)
- {
- // Addition
- case 1:
- {
- return(operand_a + operand_b);
- }
- // Subtraction
- case 2:
- {
- return(operand_a - operand_b);
- }
- // Multiplication
- case 3:
- {
- return(operand_a * operand_b);
- }
- // Division
- case 4:
- {
- if(operand_b == 0)
- {
- return 0;
- }
- return(operand_a / operand_b);
- }
- // Modulo
- case 5:
- {
- return(operand_a % operand_b);
- }
- // Exponent
- case 6:
- {
- int i;
- long int val = 1;
- if(operand_a == 0)
- {
- return(0);
- }
- if(operand_a == 1)
- {
- return(1);
- }
- if(operand_b < 0)
- {
- if(operand_a == -1)
- {
- operand_b *= -1;
- }
- else
- {
- return(0);
- }
- }
-
- for(i = 0; i < operand_b; i++)
- {
- val *= operand_a;
- }
- return(val);
- }
- // Bitwise AND
- case 7:
- {
- return(operand_a & operand_b);
- }
- // Bitwise OR
- case 8:
- {
- return(operand_a | operand_b);
- }
- // Bitwise XOR
- case 9:
- {
- return(operand_a ^ operand_b);
- }
- // Logical bitshift left
- case 10:
- {
- return(operand_a << operand_b);
- }
- // Locical bitshift right
- case 11:
- {
- return((long unsigned int)(operand_a) >> operand_b);
- }
- // Equality
- case 12:
- {
- return(operand_a == operand_b);
- }
- // less than
- case 13:
- {
- return(operand_a < operand_b);
- }
- // less than or equal to
- case 14:
- {
- return(operand_a <= operand_b);
- }
- // greater than
- case 15:
- {
- return(operand_a > operand_b);
- }
- // greater than or equal to
- case 16:
- {
- return(operand_a >= operand_b);
- }
- // not equal to
- case 17:
- {
- return(operand_a != operand_b);
- }
- default:
- {
- return(operand_a);
- }
-
- }
- }
|