~quf/computers-are-fast-2020

computers-are-fast-2020/src/18.c -rw-r--r-- 2.8 KiB
6f56515eLukas Himbert Draw the rest of the fine owl. 1 year, 7 months ago
                                                                                
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
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>

typedef enum {
  NUM,
  PLUS,
  TIMES,
  PARO,
  PARC,
  END,
} token_type_t;

token_type_t next_token(const char *b, const char **next, unsigned long long *n) {
  token_type_t ret = END;
  for (; isspace(*b); ++b);
  if (*b == '\0') {
    return END;
  }
  if (*b == '+') {
    ret = PLUS;
    ++b;
  }
  else if (*b == '*') {
    ret = TIMES;
    ++b;
  }
  else if (*b == '(') {
    ret = PARO;
    ++b;
  }
  else if (*b == ')') {
    ret = PARC;
    ++b;
  }
  else if (isdigit(*b)) {
    unsigned long long a = 0;
    for (; isdigit(*b); ++b) {
      a = 10 * a + (unsigned long long) (*b - '0');
    }
    *n = a;
    ret = NUM;
  }
  else {
    /* error, but we don't care because it never happens . */
  }
  *next = b;
  return ret;
}

typedef struct {
  token_type_t data[20];
  size_t members;
} op_stack_t;

typedef struct {
  unsigned long long data[20];
  size_t members;
} v_stack_t;

#define push(stack, val) do { \
    if (stack.members < sizeof stack.data / sizeof *stack.data) { \
      stack.data[stack.members++] = val; \
    } \
  } while (0)

#define pop(stack) ((stack.members > 0) ? stack.data[--stack.members] : 0)

#define peek(stack) ((stack.members > 0) ? stack.data[stack.members-1] : 0)

unsigned long long eval(const char *s, bool with_precedence) {
  op_stack_t ops = { 0, };
  v_stack_t vals = { 0, };

  unsigned long long n;
  token_type_t t;
  while ((t = next_token(s, &s, &n)) != END) {
    switch (t) {
      case END:
        break;
      case NUM:
        push(vals, n);
        break;
      case PLUS: /* fall through */
      case TIMES:
        while (ops.members > 0 && peek(ops) != PARO) {
          if (with_precedence && t == PLUS && peek(ops) == TIMES) {
            break;
          }
          unsigned long long a = pop(vals);
          unsigned long long b = pop(vals);
          push(vals, (pop(ops) == PLUS) ? (a + b) : (a * b));
        }
        push(ops, t);
        break;
      case PARO:
        push(ops, PARO);
        break;
      case PARC:
        while (1) {
          t = pop(ops);
          if (ops.members == 0 || t == PARO) {
            break;
          }
          unsigned long long a = pop(vals);
          unsigned long long b = pop(vals);
          push(vals, (t == PLUS) ? (a + b) : (a * b));
        }
        break;
    }
  }
  while (ops.members > 0) {
    t = pop(ops);
    unsigned long long a = pop(vals);
    unsigned long long b = pop(vals);
    push(vals, (t == PLUS) ? (a + b) : (a * b));
  }
  return pop(vals);
}

int main(void) {
  char buf[200] = { 0, };
  unsigned long long s1 = 0;
  unsigned long long s2 = 0;
  while (fgets(buf, sizeof buf, stdin) != NULL) {
    s1 += eval(buf, false);
    s2 += eval(buf, true);
  }
  printf("%llu\n", s1);
  printf("%llu\n", s2);

  return 0;
}