libmya 0.1.0
Library to parse Mya language.
Loading...
Searching...
No Matches
parse_expression.c
Go to the documentation of this file.
1#include <stdbool.h>
2
3#include "ast.h"
4#include "aststack.h"
5#include "module.h"
6#include "parser.h"
7#include "tkqueue.h"
8#include "tkstack.h"
9#include "types/operators.h"
10
11static void
12_generate_ast(module_t* module, ast_node_t* parent, tkqueue_t* queue);
13
14static unsigned int
15_parse_bitfield_expression(module_t* module, ast_node_t* parent, tkqueue_t* queue, token_t* token);
16
17static int
18_op_precedence(token_t* token);
19
20static bool
21_op_is_unary(token_t* token);
22
23unsigned int
25{
27 tkqueue_t queue;
28 token_t* current_token;
29 bool is_unary = false;
30 unsigned int ntokens = 0;
31
33 return parse_bitfield_spec(module, parent, token);
34 }
35
37 tkqueue_init(&queue, 30);
38
39 for (;;) {
40 current_token = &token[ntokens++];
41
42 switch (current_token->type) {
43 case TK_OPEN_PARENS:
44 tkstack_push(&stack, current_token);
45 is_unary = true;
46 break;
47 case TK_IDENTIFIER:
48 case TK_NUMBER:
49 tkqueue_add(&queue, current_token);
50 is_unary = false;
51 break;
52 case TK_EQUAL:
53 ntokens = _parse_bitfield_expression(module, parent, &queue, current_token);
54 goto clean_and_exit;
55 case TK_OPERATOR:
56 if (is_unary && current_token->value == OP_MINUS) {
57 current_token->value = OP_NEGATE;
58 }
59
60 while (! tkstack_isempty(&stack) && tkstack_peek(&stack)->type != TK_OPEN_PARENS &&
61 _op_precedence(tkstack_peek(&stack)) >= _op_precedence(current_token)) {
62 tkqueue_add(&queue, tkstack_pop(&stack));
63 }
64
65 tkstack_push(&stack, current_token);
66 is_unary = true;
67 break;
68 case TK_CLOSE_PARENS:
69 for (;;) {
70 token_t* popped = tkstack_pop(&stack);
71 if (! popped) {
73 module,
74 current_token->line,
75 current_token->column,
76 current_token->lexeme.length,
77 "Close parentheses here is not matching a open parentheses."
78 );
79
80 goto clean_and_exit;
81 }
82
83 if (popped->type == TK_OPEN_PARENS) {
84 break;
85 }
86
87 tkqueue_add(&queue, popped);
88 }
89
90 is_unary = false;
91 break;
92 case TK_SEMICOLON:
93 case TK_CLOSE_BRACES:
95 case TK_COMMA:
96 case TK_EOF:
97 ntokens--;
98 goto finish_expression;
99 default:
101 module,
102 current_token->line,
103 current_token->column,
104 current_token->lexeme.length,
105 "Unexpected token inside an expression."
106 );
107
108 ntokens++;
109 goto finish_expression;
110 }
111 }
112
113
114finish_expression:
115 while (! tkstack_isempty(&stack)) {
116 tkqueue_add(&queue, tkstack_pop(&stack));
117 }
118
119 _generate_ast(module, parent, &queue);
120
121clean_and_exit:
123 tkqueue_close(&queue);
124
125 return ntokens;
126}
127
128static void
129_generate_ast(module_t* module, ast_node_t* parent, tkqueue_t* queue)
130{
131 token_t* token;
133 ast_node_t left;
134 ast_node_t right;
135 ast_node_t* op;
136
138
139 for (; (token = tkqueue_get(queue));) {
140 if (token->type != TK_OPERATOR) {
142 continue;
143 }
144
145 if (_op_is_unary(token)) {
146 aststack_pop(&stack, &right);
148 ast_insert_children(op, &right);
149 continue;
150 }
151
152 aststack_pop(&stack, &right);
153 aststack_pop(&stack, &left);
155 ast_insert_children(op, &left);
156 ast_insert_children(op, &right);
157 }
158
159 if (stack.length != 1) {
160 printf("--> %d\n", stack.length);
161 module_add_error(module, parent->token->line, parent->token->column, 1, "Invalid expression starting here.");
162 goto clean;
163 }
164
165 aststack_pop(&stack, &left);
166 ast_insert_children(parent, &left);
167
168clean:
170}
171
172static unsigned int
173_parse_bitfield_expression(module_t* module, ast_node_t* parent, tkqueue_t* queue, token_t* token)
174{
175 token_t* ident = tkqueue_get(queue);
176
177 if (! ident || ident->type != TK_IDENTIFIER) {
179 module,
180 token->line,
181 token->column,
183 "Bitfield expression expects a valid identifier before the `=`, like in: `some_identifier = Field { ... }`."
184 );
185
186 return 1;
187 };
188
191
192 return 2 + parse_expression(module, op, token + 1);
193}
194
195static int
196_op_precedence(token_t* token)
197{
198 if (token == NULL) {
199 return -1;
200 }
201
202 if (token->type == TK_EQUAL) {
203 return 999;
204 }
205
206 switch (token->value) {
207 case OP_NEGATE:
208 case OP_NOT:
209 return 70;
210 case OP_DIV:
211 case OP_MULT:
212 return 60;
213 case OP_MINUS:
214 case OP_PLUS:
215 return 50;
216 case OP_SHIFT_LEFT:
217 case OP_SHIFT_RIGHT:
218 return 40;
219 case OP_AND:
220 return 30;
221 case OP_XOR:
222 return 20;
223 case OP_OR:
224 return 10;
225 default:
226 return 0;
227 }
228}
229
230static bool
231_op_is_unary(token_t* token)
232{
233 switch (token->value) {
234 case OP_NEGATE:
235 case OP_NOT:
236 return true;
237 default:
238 return false;
239 }
240}
ast_node_t * ast_insert_children(ast_node_t *parent, ast_node_t *child)
Insert a exitent AST node as children of the given parent node.
Definition ast.c:51
ast_node_t * ast_add_children(ast_node_t *parent, node_type_t type, token_t *token)
Add a new children for the given AST node.
Definition ast.c:40
void aststack_close(aststack_t *stack)
Closes the given stack.
Definition aststack.c:20
void aststack_init(aststack_t *stack)
Initializes the given stack.
Definition aststack.c:11
error_code_t aststack_pop(aststack_t *stack, ast_node_t *value)
Pop a value from the stack.
Definition aststack.c:47
ast_node_t * aststack_push(aststack_t *stack, node_type_t type, token_t *token)
Push a new value on the stack.
Definition aststack.c:27
void module_add_error(module_t *module, unsigned int line, unsigned int column, unsigned int length, const char *message)
Add error for the given module.
Definition module.c:119
@ OP_NEGATE
Definition operators.h:9
@ OP_SHIFT_LEFT
Definition operators.h:13
@ OP_NOT
Definition operators.h:10
@ OP_SHIFT_RIGHT
Definition operators.h:14
@ OP_PLUS
Definition operators.h:12
@ OP_DIV
Definition operators.h:6
@ OP_XOR
Definition operators.h:15
@ OP_MULT
Definition operators.h:8
@ OP_AND
Definition operators.h:5
@ OP_MINUS
Definition operators.h:7
@ OP_OR
Definition operators.h:11
unsigned int parse_expression(module_t *module, ast_node_t *parent, token_t *token)
Parse a mathematical expression adding it as a children on parent AST node.
unsigned int parse_bitfield_spec(module_t *module, ast_node_t *parent, token_t *token)
Parse a bitfield specification in the format Bitfield { FIELD_LIST } or Bitfield { EXPRESSION }...
token_t * token
Definition ast.h:30
unsigned int length
The length of the string.
Definition dstring.h:13
Struct that represents a Mya module.
Definition module.h:36
A struct representing a dynamic stack.
Definition aststack.h:12
unsigned int length
Number of elements on the stack.
Definition aststack.h:14
Struct for a Mya token.
Definition token.h:34
long long int value
Integer value of the token.
Definition token.h:38
token_type_t type
Token type.
Definition token.h:35
dstring_t lexeme
Lexeme of the token.
Definition token.h:41
unsigned int line
Token line inside the module.
Definition token.h:36
unsigned int column
Column of the token position on the line.
Definition token.h:37
void tkqueue_add(tkqueue_t *queue, token_t *token)
Add a value to the token queue.
Definition tkqueue.c:25
token_t * tkqueue_get(tkqueue_t *queue)
Get the current value from the queue and increment the position for the next value.
Definition tkqueue.c:32
void tkqueue_init(tkqueue_t *queue, unsigned int initial_size)
Initializes the token queue.
Definition tkqueue.c:9
void tkqueue_close(tkqueue_t *queue)
Close the given queue.
Definition tkqueue.c:18
token_t * tkstack_peek(tkstack_t *stack)
Peeks the value on top of the stack without removing it.
Definition tkstack.c:45
bool tkstack_isempty(tkstack_t *stack)
Check if the given stack is empty.
Definition tkstack.c:55
token_t * tkstack_pop(tkstack_t *stack)
Pop a value from the stack.
Definition tkstack.c:35
void tkstack_close(tkstack_t *stack)
Closes the given stack.
Definition tkstack.c:20
void tkstack_init(tkstack_t *stack)
Initializes the given stack.
Definition tkstack.c:11
void tkstack_push(tkstack_t *stack, token_t *token)
Push a new value on the stack.
Definition tkstack.c:27
struct ast_node ast_node_t
@ NT_EXPRESSION
Definition ast.h:14
struct stack aststack_t
A struct representing a dynamic stack.
struct module module_t
Struct that represents a Mya module.
struct tkqueue tkqueue_t
Queue of tokens.
struct tkstack tkstack_t
A struct representing a dynamic stack of token_t pointers.
struct token token_t
Struct for a Mya token.
@ TK_NUMBER
Definition token.h:21
@ TK_IDENTIFIER
Definition token.h:19
@ TK_OPEN_BRACES
Definition token.h:22
@ TK_OPEN_PARENS
Definition token.h:24
@ TK_COMMA
Definition token.h:16
@ TK_CLOSE_PARENS
Definition token.h:14
@ TK_OPERATOR
Definition token.h:25
@ TK_CLOSE_BRACKET
Definition token.h:13
@ TK_EOF
Definition token.h:17
@ TK_CLOSE_BRACES
Definition token.h:12
@ TK_EQUAL
Definition token.h:18
@ TK_SEMICOLON
Definition token.h:26