summaryrefslogtreecommitdiff
path: root/tiger-compiler/src/llvmtranslate/tiger-runtime.c
blob: f952e0f8c4c8e5f84d465ce776689d1a97211056 (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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/**
   \file llvm/tiger-runtime.c
   \brief C Implementation of the Tiger runtime.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

#define EXIT_RUNTIME_FAILURE 120

// FWD, declared by tc
void tc_main(int);

/** \name Internal functions (calls generated by the compiler only). */
/** \{ */

/** \brief Allocate an array and fill it with a default value.
    \param size    The size of the array.
    \param elt     The default element.

    An element size is always the size of a word on 32-bit systems.
*/
int *tc_init_array(int size, int elt)
{
  int *arr = (int *)malloc(size * sizeof (elt));
  for (size_t i = 0; i < size; ++i)
    arr[i] = elt;
  return arr;
}
/** \} */

/** \name Miscellaneous */
/** \{ */

/** \brief Equivalent to operator! in C.
    \param i       The integer to be inversed.
*/
int tc_not(int i)
{
  return !i;
}

/** \brief Exit the program with the desired status.
    \param status  The status code.
*/
void tc_exit(int status)
{
  exit(status);
}
/** \} */

/** \name Operations on strings. */
/** \{ */

// Small trick. Add a \0 after each char in the consts
// This is filled in tc_main
static char consts[512] = { 0 };

/** \brief Get a string containing the character represented by the ascii value
 *         of \a i.
    \param i  The ascii value of the desired character.
*/
const char *tc_chr(int i)
{
  if (!(0 <= i && i <= 255))
  {
    fputs("chr: character out of range\n", stderr);
    exit(EXIT_RUNTIME_FAILURE);
  }
  return consts + i * 2;
}

/** \brief Concatenate two strings.
    \param a  The first string.
    \param b  The second string.
*/
const char *tc_concat(const char *a, const char *b)
{
  size_t len_a = strlen(a);
  size_t len_b = strlen(b);
  if (len_a == 0)
    return b;
  else if (len_b == 0)
    return a;
  else
  {
    int i = 0;
    int n = len_a + len_b;
    char *t = (char *) malloc(n + 1);
    for (i = 0; i < len_a; i++)
      t[i] = a[i];
    for (i = 0; i < len_b; i++)
      t[i + len_a] = b[i];
    t[n] = '\0';
    return t;
  }
}

/** \brief Get the ascii value of a character.
    \param s  The string representing the desired character to be converted.

    Inverse of `tc_chr`.
*/
int tc_ord(const char *s)
{
  size_t len = strlen(s);
  if (len == 0)
    return -1;
  else
    return s[0];
}

/** \brief Get the size of a string.
    \param s  The string.
*/
int tc_size(const char *s)
{
  return strlen(s);
}

/** \brief Return a part of the string \a s.
    \param s       The source string
    \param first   The first character of the extraction (starting at 0)
    \param n       The number of characters to get.

    \a first and \a n must be positive, and one shall not go beyond the size
    of \a s.  Otherwise, exit with runtime failure.
*/
const char *tc_substring(const char *s, int first, int n)
{
  size_t len = strlen(s);
  if (!(0 <= first
        && 0 <= n
        && first + n <= len))
  {
    fputs("substring: arguments out of bounds\n", stderr);
    exit(EXIT_RUNTIME_FAILURE);
  }

  if (n == 1)
    return consts + s[first] * 2;
  else
  {
    char *t = (char *) malloc(n + 1);
    for (int i = 0; i < n; i++)
      t[i] = s[first + i];
    t[n] = '\0';
    return t;
  }
}

/** \brief Compare two strings.
    \param lhs       The first string.
    \param rhs       The second string.
*/
int tc_strcmp(const char *lhs, const char *rhs)
{
  return strcmp(lhs, rhs);
}

/** \brief Return a part of the string \a s.
    \param s       The source string
    \param first   The first character of the extraction (starting at 0)
    \param n       The number of characters to get.

    \a first and \a n must be positive, and one shall not go beyond the size
    of \a s.  Otherwise, exit with runtime failure.
*/
int tc_streq(const char *lhs, const char *rhs)
{
  return strcmp(lhs, rhs) == 0;
}
/** \} */

/** \name Input/Output. */
/** \{ */

/** \brief Get a character from the standard input.
*/
const char *tc_getchar()
{
  int i = getc(stdin);
  if (i == EOF)
    return "";
  else
    return consts + i * 2;
}

/** \brief Print a string on the standard output.
    \param s   The string to be printed.
*/
void tc_print(const char *s)
{
  printf("%s", s);
}

/** \brief Print a string on the standard error.
    \param s   The string to be printed.
*/
void tc_print_err(const char *s)
{
  fprintf(stderr, "%s", s);
}

/** \brief Print an int on the standard error.
    \param i   The int to be printed.
*/
void tc_print_int(int i)
{
  printf("%d", i);
}

/** \brief Flush the standard output.
*/
void tc_flush()
{
  fflush(stdout);
}

/** \} */

/** \name Custom primitives. */
/** \{ */

/** \brief Terminate the program with an error if condition if false
    \param condition Condition to assert, represented as a Tiger 32 bits integer
    \param instruction_str The condition represented as a string, used for
    pretty-printing. Can be NULL
    \param filename File in which the assertion comes from. Can be NULL
*/
void tc_assertion(const int condition, const char* instruction_str,
                  const char* filename)
{
  if (condition)
    {
      return;
    }

  if (instruction_str == NULL)
    {
      instruction_str = "";
    }

  if (filename == NULL)
    {
      filename = "";
    }

  fprintf(stderr, "%s: %s assertion is false. aborting\n", filename,
          instruction_str);
  abort();
}

/**
 * \brief Proceed to a fork syscall and return the resulting process id.
 * \return the resulting pid for the parent, 0 for the child, or -1 if the
 * process forking failed
 */
int tc_fork()
  {
    return fork();
  }

/**
 * \brief Wait for the process specified by the provided id to end and return
 * the resulting status code.
 * \param pid a process, referenced by its identifier
 * \return the process' status code
 */
int tc_wait_pid(int pid)
  {
    int status_code = -1;
    waitpid(pid, &status_code, WUNTRACED | WCONTINUED);
    return status_code;
  }

/**
 * \brief Determine the exit code specified by a status code and return it.
 * \param status_code any process status code
 * \return the implied exit code
 */
int tc_get_exit_code(int status_code)
  {
    return WEXITSTATUS(status_code);
  }

/** \} */

int main()
{
  // Fill the `consts` array with every character in the ascii table, followed
  // by a null character.
  for (int i = 0; i < 512; i += 2)
  {
    consts[i] = i / 2;
    consts[i + 1] = 0;
  }

  tc_main(0);
  return 0;
}