summaryrefslogtreecommitdiff
path: root/elf/eval.c
blob: 59eb234166a645538389038a26a7a79a1310e2a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>

static void *funcall (char **stringp);
static void *eval (char **stringp);

static void *
funcall (char **stringp)
{
  void *args[strlen (*stringp)], **ap = args;
  void *argcookie = &args[1];

  do
    {
      /* Evaluate the next token.  */
      *ap++ = eval (stringp);

      /* Whitespace is irrelevant.  */
      while (isspace (**stringp))
	++*stringp;

      /* Terminate at closing paren or end of line.  */
    } while (**stringp != '\0' && **stringp != ')');
  if (**stringp != '\0')
    /* Swallow closing paren.  */
    ++*stringp;

  if (args[0] == NULL)
    {
      static const char unknown[] = "Unknown function\n";
      write (1, unknown, sizeof unknown - 1);
      return NULL;
    }

  /* Do it to it.  */
  __builtin_return (__builtin_apply (args[0],
				     &argcookie,
				     (char *) ap - (char *) &args[1]));
}

static void *
eval (char **stringp)
{
  void *value;
  char *p = *stringp, c;

  /* Whitespace is irrelevant.  */
  while (isspace (*p))
    ++p;

  switch (*p)
    {
    case '"':
      /* String constant.  */
      value = ++p;
      do
	if (*p == '\\')
	  {
	    switch (*strcpy (p, p + 1))
	      {
	      case 't':
		*p = '\t';
		break;
	      case 'n':
		*p = '\n';
		break;
	      }
	    ++p;
	  }
      while (*p != '\0' && *p++ != '"');
      if (p[-1] == '"')
	p[-1] = '\0';
      break;

    case '(':
      *stringp = ++p;
      return funcall (stringp);

    default:
      /* Try to parse it as a number.  */
      value = (void *) strtol (p, stringp, 0);
      if (*stringp != p)
	return value;

      /* Anything else is a symbol that produces its address.  */
      value = p;
      do
	++p;
      while (*p != '\0' && !isspace (*p) && (!ispunct (*p) || *p == '_'));
      c = *p;
      *p = '\0';
      value = dlsym (NULL, value);
      *p = c;
      break;
    }

  *stringp = p;
  return value;
}


void
_start (void)
{
  char *buf = NULL;
  size_t bufsz = 0;

  while (getline (&buf, &bufsz, stdin) > 0)
    {
      char *p = buf;
      eval (&p);
    }

  exit (0);
}