git @ Cat's Eye Technologies Maentwrog / master src / rdp.c
master

Tree @master (Download .tar.gz)

rdp.c @masterraw · history · blame

/*

   rdp.c

   a recursive decent parser (origins now lost, sorry)

   Chris Pressey, March, like, 7th, 1994

   This program is by no means complete, but it's as far as I'll
   go in the general case.  It should be no problem adapting it
   to do all sorts of really demented things.

   This work is in the public domain.  See the file UNLICENSE for more info.

 */

#define THIS_PROGRAM_IS_NOT_REALLY_AS_CRAPPY_AS_YOU_THINK

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define T_DELIMITER     0       /* delimeter token */
#define T_VARIABLE      1
#define T_CONSTANT      2

#define T_LENGTH        80

int toktype;                    /* type of last token */
char token[T_LENGTH];           /* what gettoken returns - a token */
char prog[T_LENGTH];            /* the string to parse */

int t;                          /* a 'pointer' to the pos in prog[] */
int result;                     /* result of calculations */
int vars[26];                   /* variables */

int level2 (int result);        /* recursion levels.  level 1 is no */
int level3 (int result);        /* longer needed (it assigned vars) */
int level4 (int result);
int level5 (int result);
int level6 (int result);
int primitive (int result);

int isdelimeter (char);
void gettoken (void);
void putback (void);
void serror (int);
int arith (char, int, int);
int findvar (char *);
int getexp (int);

/*-------------------------------------------------------------------------*/

int 
isdelimeter (char ch)
{
  switch (ch)
    {
    case ' ':
    case '+':
    case '-':
    case '/':
    case '*':
    case '%':
    case '=':
    case '>':
    case '<':
    case '(':
    case ')':
    case '$':
    case '!':
    case '&':
    case '|':
    case '^':
      return 1;
      break;

    default:
      return 0;
    }
}

void 
gettoken ()
{
  strcpy (token, "");
  token[1] = (char) 0;

  while (isspace ((int)prog[t]))
    t++;
  if (prog[t] == '$')
    strcpy (token, "$");
  if (isdelimeter (prog[t]))
    {
      toktype = T_DELIMITER;
      token[0] = prog[t++];
    }
  else
    {
      if (isalpha ((int)prog[t]))
        {
          toktype = T_VARIABLE;
          while (!(isdelimeter (prog[t])))
            {
              token[strlen (token) + 1] = (char) 0;
              token[strlen (token)] = prog[t++];
            }
        }
      else if (isdigit ((int)prog[t]))
        {
          toktype = T_CONSTANT;
          while (!(isdelimeter (prog[t])))
            {
              token[strlen (token) + 1] = (char) 0;
              token[strlen (token)] = prog[t++];
            }
        }
    }
}

void 
putback ()
{
  t -= strlen (token);
}

void 
serror (int s)
{
  switch (s)
    {
    case 1:
      printf ("syntax error\n");
      break;
    case 2:
      printf ("mismatched parentheses\n");
      break;
    case 3:
      printf ("expression absent\n");
      break;
    }
}

/*
   if you define a new operator, use

   return (argument op operand)

   if you define a function (eg. sin(x)), use

   return (func(operand))

   if you define a backwards function (eg. x!) use

   return (func(argument))

   unary operators (such as -5 and !(a=b)) are not handled here, but are
   handled in level5()

 */
int 
arith (char op, int argument, int operand)
{
  switch (op)
    {
    case '+':
      return (argument + operand);      /* addition */
    case '-':
      return (argument - operand);      /* subtraction */
    case '*':
      return (argument * operand);      /* multiplication */
    case '/':
      return (argument / operand);      /* division */
    case '%':
      return (argument % operand);      /* modulus */
    case '=':
      return (argument == operand);     /* equality */
    case '>':
      return (argument > operand);      /* superiority */
    case '<':
      return (argument < operand);      /* inferiority */
    case '&':
      return (argument & operand);      /* binary AND */
    case '|':
      return (argument | operand);      /* binary OR */
    case '^':
      return (argument ^ operand);      /* binary XOR */
    }
    exit(1);
}

int 
findvar (char *s)
{
  return vars[(int) toupper ((int)s[0]) - (int) 'A'];
}

int 
getexp (int result)
{
  gettoken ();
  if (strlen (token))
    result = level2 (result);
  else
    serror (3);
  return result;
}

int 
level2 (int result)
{
  char op;
  int hold = 0;

  result = level3 (result);
  op = token[0];
  while ((op == '+') || (op == '-'))
    {
      gettoken ();
      hold = level3 (hold);
      result = arith (op, result, hold);
      op = token[0];
    }
  return result;
}

int 
level3 (int result)
{
  char op;
  int hold = 0;

  result = level4 (result);
  op = token[0];
  while ((op == '*') || (op == '/'))
    {
      gettoken ();
      hold = level4 (hold);
      result = arith (op, result, hold);
      op = token[0];
    }
  return result;
}

int 
level4 (int result)
{
  int hold = 0;
  char ch;

  result = level5 (result);
  ch = token[0];
  switch (ch)
    {
    case '=':
    case '>':
    case '<':
    case '&':
    case '|':
    case '^':
      gettoken ();
      hold = level4 (hold);
      result = arith (ch, result, hold);
      break;
    }
  return result;
}

int 
level5 (int result)
{
  char op;

  op = ' ';
  if ((toktype == T_DELIMITER) && ((token[0] == '+') || (token[0] == '-')))
    {
      op = token[0];
      gettoken ();
    }
  result = level6 (result);
  if (op == '-')
    result *= (-1);
  if (op == '!')
    result = !result;
  return result;
}

int 
level6 (int result)
{
  if ((token[0] == '(') && (toktype == T_DELIMITER))
    {
      gettoken ();
      result = level2 (result);
      if (token[0] != ')')
        serror (2);
      gettoken ();
    }
  else
    result = primitive (result);
  return result;
}

int 
primitive (int result)
{
  if (toktype == T_CONSTANT)
    result = atoi (token);
  else if (toktype == T_VARIABLE)
    result = findvar (token);
  else
    serror (1);
  gettoken ();
  return result;
}

int 
main (int argc, char **argv)
{
  argc = argc;
  {
    int c;
    for (c = 0; c <= 25; c++)
      vars[c] = 0;
  }
  t = 0;

  strcpy (prog, argv[1]);
  strcat (prog, "$");
  result = getexp (result);
  printf ("%d\n", result);
  exit (0);




#ifdef THIS_PROGRAM_IS_NOT_REALLY_AS_CRAPPY_AS_YOU_THINK
}
#else
}
#endif