├── .vscode
└── settings.json
├── grammar.txt
├── license.md
├── lowfish
├── makefile
├── out.txt
├── readme.md
├── src
├── il
│ ├── il.c
│ └── il.h
├── lexer
│ ├── lexer.c
│ └── lexer.h
├── main.c
├── optimizer
│ └── optimizer.h
├── parser
│ ├── parser.c
│ └── parser.h
├── typechecker
│ ├── typechecker.c
│ └── typechecker.h
├── util.c
└── util.h
├── test.lf
└── tests
├── few_call.lf
├── fun.lf
├── fun.lf.expected
├── funcall.lf
├── funcall.lf.expected
├── test.py
├── variable.lf
├── variable.lf.expected
├── variable_func_call.lf
└── variable_func_call.lf.expected
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "typechecker.h": "c",
4 | "array": "c",
5 | "compare": "c",
6 | "functional": "c",
7 | "tuple": "c",
8 | "type_traits": "c",
9 | "utility": "c",
10 | "istream": "c",
11 | "ostream": "c"
12 | }
13 | }
--------------------------------------------------------------------------------
/grammar.txt:
--------------------------------------------------------------------------------
1 | grammar lowfish;
2 |
3 | program: (function | struct | enum | (extern SEMI))* EOF;
4 | struct:
5 | 'struct' ID BEGINOFBLOCK (vardecl SEMI)* ENDOFBLOCK |
6 | 'struct' ID (vardecl SEMI)* 'end';
7 | enum:
8 | 'enum' ID BEGINOFBLOCK (expression SEMI) * ENDOFBLOCK |
9 | 'enum' ID (expression SEMI)* 'end';
10 |
11 | function: type ID OPENBR vardecl* CLOSEBR block;
12 | block: normal_block | arrow_block;
13 | normal_block: begin line* end;
14 | arrow_block: ARROW (expression | conditional | booleanexpression | vardecl | native) (end | SEMI );
15 | begin: BEGINOFBLOCK;
16 | end: ENDOFBLOCK;
17 | line: ((expression SEMI) | (conditional) | (booleanexpression SEMI) | (vardecl SEMI) | (native SEMI) ) ('\n')?;
18 | extern:
19 | 'extern' OPENBR STRING CLOSEBR;
20 | asm:
21 | 'asm' OPENBR STRING CLOSEBR;
22 | basic_expression:
23 | 'true' |
24 | 'false'|
25 | STRING |
26 | NUMBER |
27 | ID;
28 | functioncall:
29 | ID args;
30 | args:
31 | OPENBR (expression)? ((COMMA expression)*)? CLOSEBR;
32 | binexpr:
33 | basic_expression PLUS basic_expression |
34 | basic_expression MINUS basic_expression |
35 | basic_expression DIV basic_expression |
36 | basic_expression MUL basic_expression |
37 | basic_expression MOD basic_expression |
38 | basic_expression LOGICALOR basic_expression |
39 | basic_expression XOR basic_expression |
40 | basic_expression LOGICALAND basic_expression |
41 | binexpr PLUS binexpr |
42 | binexpr MINUS binexpr |
43 | binexpr DIV binexpr |
44 | binexpr MUL binexpr |
45 | binexpr MOD binexpr |
46 | binexpr LOGICALOR binexpr |
47 | binexpr XOR binexpr |
48 | binexpr LOGICALAND binexpr;
49 | PLUS:
50 | '+';
51 | MINUS:
52 | '-';
53 | DIV:
54 | '/';
55 | MUL:
56 | '*';
57 | MOD:
58 | '%';
59 | LOGICALOR:
60 | '|';
61 | XOR:
62 | '^';
63 | LOGICALAND:
64 | '&';
65 | expression:
66 | basic_expression |
67 | ID index |
68 | expression index |
69 | OPENBR type CLOSEBR expression |
70 | binexpr |
71 | assignment |
72 | 'return' basic_expression
73 | | functioncall;
74 | assignment:
75 | ID equal;
76 | simplebooleanexpr:
77 | expression |
78 | eq |
79 | noteq|
80 | EXCLAMATION expression |
81 | expression MORE expression |
82 | expression LESS expression |
83 | expression MOREEQUAL expression |
84 | expression LESSEQUAL expression;
85 | booleanexpression:
86 | OPENBR booleanexpression CLOSEBR |
87 | simplebooleanexpr |
88 | simplebooleanexpr BOOLNOTEQUAL simplebooleanexpr |
89 | simplebooleanexpr BOOLEQUAL simplebooleanexpr |
90 | EXCLAMATION simplebooleanexpr |
91 | simplebooleanexpr MORE simplebooleanexpr |
92 | simplebooleanexpr LESS simplebooleanexpr |
93 | simplebooleanexpr MOREEQUAL simplebooleanexpr |
94 | simplebooleanexpr LESSEQUAL simplebooleanexpr |
95 | simplebooleanexpr BOOLAND simplebooleanexpr |
96 | simplebooleanexpr BOOLOR simplebooleanexpr;
97 | eq:
98 | expression BOOLEQUAL expression;
99 | noteq:
100 | expression BOOLNOTEQUAL expression;
101 | conditional:
102 | if |
103 | while |
104 | repeat |
105 | for |
106 | unless |
107 | else;
108 | if:
109 | 'if' booleanexpression blo
110 | ck;
111 | while:
112 | 'while' booleanexpression block;
113 | repeat:
114 | 'repeat' expression ARROW expression block;
115 | for:
116 | 'for' (vardecl | ID) COMMA expression ARROW expression block ;
117 | else:
118 | 'else' block |
119 | 'else' conditional;
120 | unless:
121 | 'unless' booleanexpression block ;
122 |
123 | type: (struct ID) | void | i64 | i32 | i16 | i8 | u64 | u32 | u16 | u8 | ptr8 | ptr16 | ptr32 | ptr64;
124 | void: 'void';
125 | i64: 'i64';
126 | i32: 'i32';
127 | i16: 'i16';
128 | i8: 'i8';
129 | u64: 'u64';
130 | u32: 'u32';
131 | u16: 'u16';
132 | u8: 'u8';
133 | ptr64: 'ptr64';
134 | ptr32: 'ptr32';
135 | ptr16: 'ptr16';
136 | ptr8: 'ptr8';
137 |
138 | equal:
139 | EQUAL basic_expression |
140 | EQUAL expression;
141 |
142 | vardecl:
143 | type ID (equal)?
144 | | type index (EQUAL BEGINOFBLOCK expression COMMA* ENDOFBLOCK)?;
145 | index:
146 | INDEXBROPEN expression INDEXBRCLOSE;
147 | SEMI:
148 | ';';
149 | COMMENT: '#' ~[\r\n]* -> channel(HIDDEN);
150 | WS: [ \t\r\n]+ -> skip;
151 | ID: [a-zA-Z_][a-zA-Z0-9_]*;
152 | NUMBER: DIGIT+ ('.' DIGIT+)?;
153 | fragment DIGIT: [0-9];
154 | STRING: '"'(.*?)'"';
155 | BEGINOFBLOCK: '{';
156 | ENDOFBLOCK: '}';
157 | OPENBR: '(';
158 | CLOSEBR: ')'
159 | EQUAL: '=';
160 | BOOLNOTEQUAL: '!=';
161 | BOOLEQUAL: '==';
162 | EXCLAMATION: '!';
163 | INDEXBROPEN: '[';
164 | INDEXBRCLOSE: ']';
165 | MORE: '>';
166 | ARROW: '->';
167 | LESS: '<';
168 | MOREEQUAL: '>=';
169 | LESSEQUAL: '<=';
170 | BOOLOR: '||';
171 | BOOLAND: '&&';
172 | LOGICALAND: '&';
173 | LOGICALOR: '|';
174 | XOR: '^';
175 | PLUS: '+';
176 | MINUS: '-';
177 | DIV: '/';
178 | MUL: '*';
--------------------------------------------------------------------------------
/license.md:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/lowfish:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpaceFishDev/LowFish/22554fc400895ede6119ae804186360241924645/lowfish
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | src := $(wildcard src/*.c) $(wildcard src/lexer/*.c) $(wildcard src/parser/*.c) $(wildcard src/typechecker/*.c) $(wildcard src/il/*.c)
2 | out := lowfish
3 | cflags := -Isrc/
4 |
5 | all: $(src)
6 | gcc $(src) $(cflags) -o $(out) -std=c99
7 | ./$(out)
8 | debug: $(src)
9 | gcc $(src) $(cflags) -o $(out) -g
10 | gdb ./$(out)
11 |
--------------------------------------------------------------------------------
/out.txt:
--------------------------------------------------------------------------------
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 | WARNING: UNSAFE FUNCTION DEFINITION FOR 'printf': The type checker is unable to check functions used from extern make sure that you match the argument count and type.
30 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Lowfish
2 | Lowfish is a low level compiled programming language.
3 |
4 | ## Features
5 | - types that make sense ie 'i32' or 'ptr32'
6 | - open source, so if you have a complaint and I'm too slow, fix it.
7 | - other stuff
8 |
9 | ### Hello world.
10 | ```c
11 | extern("printf")
12 | i32 main()
13 | {
14 | printf("Hello, World");
15 | }
16 | ```
17 |
--------------------------------------------------------------------------------
/src/il/il.c:
--------------------------------------------------------------------------------
1 | #include "il.h"
2 |
3 | #include
4 |
5 | #include "../typechecker/typechecker.h"
6 |
7 | node **get_mul(node **list, int *len, node *p)
8 | {
9 |
10 | if (p->type == BASICEXPRESSION)
11 | {
12 | return list;
13 | }
14 | node *op = p;
15 | if (p->type == BINEXPR)
16 | {
17 | op = p->children[0];
18 | }
19 | if (op->node_token.type == MUL)
20 | {
21 | list[*len] = op;
22 | list = realloc(list, (*len + 1) * sizeof(node *));
23 | ++len[0];
24 | }
25 | if (op->n_child == 2)
26 | {
27 | get_mul(list, len, op->children[0]);
28 | get_mul(list, len, op->children[1]);
29 | }
30 | return list;
31 | }
32 | bool continuing = false;
33 | char *visit_node(il_generator *il_gen, node *curr)
34 | {
35 | if (!curr)
36 | {
37 | return "";
38 | }
39 | if (curr->parent && curr->parent->type == PROGRAM)
40 | {
41 | if (!continuing)
42 | {
43 | continuing = true;
44 | char *res = visit_node(il_gen, curr);
45 | int c = 0;
46 | for (int i = 0; i < curr->parent->n_child; ++i)
47 | {
48 | if (curr->parent->children[i] == curr)
49 | {
50 | c = i;
51 | break;
52 | }
53 | }
54 | c += 1;
55 | if (c >= curr->parent->n_child)
56 | {
57 | return res;
58 | }
59 | char *o = visit_node(il_gen, curr->parent->children[c]);
60 | char *buf = malloc(strlen(res) + strlen(o) + 2);
61 | buf[strlen(res) + strlen(o) + 1] = 0;
62 | strcpy(buf, res);
63 | strcat(buf, "\n");
64 | strcat(buf, o);
65 | return buf;
66 | }
67 | if (continuing)
68 | {
69 | continuing = false;
70 | }
71 | }
72 | switch (curr->type)
73 | {
74 | case FUNCTION:
75 | {
76 | char *out = malloc(strlen("function ") +
77 | strlen(curr->children[1]->node_token.text));
78 | sprintf(out, "function %s\n", curr->children[1]->node_token.text);
79 |
80 | node *block = curr->children[2];
81 | for (int i = 0; i < block->n_child; ++i)
82 | {
83 | char *str = visit_node(il_gen, block->children[i]);
84 | int x = strlen(str);
85 | out = realloc(out, x + strlen(out) + 2);
86 | strcat(out, str);
87 | strcat(out, "\n");
88 | free(str);
89 | }
90 |
91 | return out;
92 | }
93 | case FUNCTION_CALL:
94 | {
95 | if (curr->n_child > 0)
96 | {
97 | if (curr->children[0]->type == BASICEXPRESSION)
98 | {
99 | char *fmt = "call %s %s";
100 | char *buff = malloc(400);
101 | sprintf(buff, fmt, curr->node_token.text, curr->children[0]->children[0]->node_token.text);
102 | return buff;
103 | }
104 | }
105 | }
106 | case TOKENNODE:
107 | {
108 | if (curr->node_token.type == MUL)
109 | {
110 | char *left;
111 | char *right;
112 | left = visit_node(il_gen, curr->children[0]);
113 | right = visit_node(il_gen, curr->children[1]);
114 | char *fmt = "%s mul %s";
115 | char *out = malloc(100);
116 | sprintf(out, fmt, left, right);
117 | free(left);
118 | free(right);
119 | return out;
120 | }
121 | }
122 | case EXTERN:
123 | {
124 | if (curr->children[0]->type == TOKENNODE)
125 | {
126 | char *fmt = "extern %s";
127 | char *out = malloc(100);
128 | sprintf(out, fmt, curr->children[0]->node_token.text);
129 | return out;
130 | }
131 | }
132 | break;
133 | case BINEXPR:
134 | {
135 | if (curr->n_child > 0)
136 | {
137 | if (curr->children[0]->node_token.type == MUL)
138 | {
139 | char *left;
140 | char *right;
141 | left = visit_node(il_gen, curr->children[0]->children[0]);
142 | right = visit_node(il_gen, curr->children[0]->children[1]);
143 | char *fmt = "%s mul %s";
144 | char *out = malloc(100);
145 | sprintf(out, fmt, left, right);
146 | free(left);
147 | free(right);
148 | return out;
149 | }
150 | if (curr->children[0]->node_token.type == DIV)
151 | {
152 | char *left;
153 | char *right;
154 | left = visit_node(il_gen, curr->children[0]->children[0]);
155 | right = visit_node(il_gen, curr->children[0]->children[1]);
156 | char *fmt = "%s div %s";
157 | char *out = malloc(100);
158 | sprintf(out, fmt, left, right);
159 | free(left);
160 | free(right);
161 | return out;
162 | }
163 | int len = 0;
164 | node **multiplications = get_mul(malloc(sizeof(node *)), &len, curr);
165 | if (len == 0)
166 | {
167 | if (curr->children[0]->node_token.type == PLUS)
168 | {
169 | char *left;
170 | char *right;
171 | left = visit_node(il_gen, curr->children[0]->children[0]);
172 | right = visit_node(il_gen, curr->children[0]->children[1]);
173 | char *fmt = "%s add %s";
174 | char *out = malloc(100);
175 | sprintf(out, fmt, left, right);
176 | free(left);
177 | free(right);
178 | return out;
179 | }
180 | char *left;
181 | char *right;
182 | left = visit_node(il_gen, curr->children[0]->children[0]);
183 | right = visit_node(il_gen, curr->children[0]->children[1]);
184 | char *fmt = "%s sub %s";
185 | char *out = malloc(100);
186 | sprintf(out, fmt, left, right);
187 | free(left);
188 | free(right);
189 | return out;
190 | }
191 | char *out = malloc(1000);
192 | for (int i = 0; i < len; ++i)
193 | {
194 | char *x = visit_node(il_gen, multiplications[i]);
195 | strcat(out, x);
196 | }
197 | char *str = malloc(100);
198 | char *fmt = " add %s";
199 | sprintf(str, fmt, visit_node(il_gen, curr->children[0]->children[0]));
200 | strcat(out, str);
201 | free(str);
202 | return out;
203 | }
204 | }
205 | break;
206 | case BASICEXPRESSION:
207 | {
208 | switch (curr->children[0]->node_token.type)
209 | {
210 | case NUMBER:
211 | {
212 | return curr->children[0]->node_token.text;
213 | }
214 | break;
215 | }
216 | }
217 | break;
218 | default:
219 | {
220 | return visit_node(il_gen, curr->children[0]);
221 | }
222 | }
223 | }
224 |
225 | char *generate_il(node *root, typechecker *type_checker)
226 | {
227 | il_generator generator =
228 | (il_generator){root, root, 0, malloc(1), type_checker};
229 | char *src = visit_node(&generator, root);
230 | generator.src = src;
231 | return generator.src;
232 | }
233 |
--------------------------------------------------------------------------------
/src/il/il.h:
--------------------------------------------------------------------------------
1 | #include "../typechecker/typechecker.h"
2 |
3 | typedef struct
4 | {
5 | node *root;
6 | node *current;
7 | size_t length_of_src;
8 | char *src; // generated source code NOT the input source code!
9 | typechecker *type_checker;
10 | int parent_idx;
11 | } il_generator;
12 | #define append_src(_src) \
13 | il_gen->src = \
14 | realloc(il_gen->src, il_gen->length_of_src + strlen(_src) + 2); \
15 | il_gen->length_of_src += strlen(_src) + 1; \
16 | strcat(il_gen->src, _src); \
17 | il_gen->src[il_gen->length_of_src - 1] = '\n'; \
18 | il_gen->src[il_gen->length_of_src] = 0;
19 | #define append_src_no_nl(_src) \
20 | il_gen->src = \
21 | realloc(il_gen->src, il_gen->length_of_src + strlen(_src) + 1); \
22 | il_gen->length_of_src += strlen(_src); \
23 | strcat(il_gen->src, _src); \
24 | il_gen->src[il_gen->length_of_src] = 0;
25 |
26 | char *visit_node(il_generator *generator, node *curr);
27 |
28 | char *generate_il(node *root, typechecker *type_checker);
29 |
--------------------------------------------------------------------------------
/src/lexer/lexer.c:
--------------------------------------------------------------------------------
1 | #include "lexer.h"
2 |
3 | char *mkstr(char *str)
4 | {
5 | char *new = malloc(strlen(str) + 1);
6 | memset(new, 0, strlen(str) + 1);
7 | strcpy(new, str);
8 | return new;
9 | }
10 |
11 | bool is_digit(char c) { return c >= '0' && c <= '9'; }
12 |
13 | token lex(lexer *Lexer)
14 | {
15 | if (Lexer->pos > strlen(Lexer->src))
16 | {
17 | return create_token(Lexer->column, Lexer->line, mkstr("\0"),
18 | END_OF_FILE);
19 | }
20 | switch (Lexer->src[Lexer->pos])
21 | {
22 | case '\0':
23 | {
24 | return create_token(Lexer->column, Lexer->line, mkstr("\0"),
25 | END_OF_FILE);
26 | }
27 | break;
28 | #pragma region SYMBOLS
29 |
30 | case '{':
31 | {
32 | next;
33 | return create_token(Lexer->column, Lexer->line, mkstr("{"),
34 | BEGINOFBLOCK);
35 | }
36 | case '}':
37 | {
38 | next;
39 | return create_token(Lexer->column, Lexer->line, mkstr("}"),
40 | ENDOFBLOCK);
41 | }
42 | case '(':
43 | {
44 | next;
45 | return create_token(Lexer->column, Lexer->line, mkstr("("), OPENBR);
46 | }
47 | case ')':
48 | {
49 | next;
50 | return create_token(Lexer->column, Lexer->line, mkstr(")"),
51 | CLOSEBR);
52 | }
53 |
54 | case '&':
55 | {
56 | next;
57 | if (Lexer->src[Lexer->pos] >= 'a' &&
58 | Lexer->src[Lexer->pos] <= 'z' ||
59 | Lexer->src[Lexer->pos] >= 'A' &&
60 | Lexer->src[Lexer->pos] <= 'Z' ||
61 | Lexer->src[Lexer->pos] == '_')
62 | {
63 | size_t start = Lexer->pos;
64 | size_t column = Lexer->column;
65 | size_t line = Lexer->line;
66 | while (Lexer->src[Lexer->pos] >= 'A' &&
67 | Lexer->src[Lexer->pos] <= 'Z' ||
68 | Lexer->src[Lexer->pos] >= 'a' &&
69 | Lexer->src[Lexer->pos] <= 'z' ||
70 | Lexer->src[Lexer->pos] == '_' ||
71 | is_digit(Lexer->src[Lexer->pos]))
72 | {
73 | next;
74 | }
75 | size_t len = Lexer->pos - start;
76 | char *result = malloc(len + 1);
77 | result[len] = 0;
78 | Lexer->pos = start;
79 | while (Lexer->src[Lexer->pos] >= 'A' &&
80 | Lexer->src[Lexer->pos] <= 'Z' ||
81 | Lexer->src[Lexer->pos] >= 'a' &&
82 | Lexer->src[Lexer->pos] <= 'z' ||
83 | Lexer->src[Lexer->pos] == '_' ||
84 | is_digit(Lexer->src[Lexer->pos]))
85 | {
86 | result[Lexer->pos - start] = Lexer->src[Lexer->pos];
87 | next;
88 | }
89 | return create_token(column, line, result, REF);
90 | }
91 | if (Lexer->src[Lexer->pos] == '&')
92 | {
93 | next;
94 | return create_token(Lexer->column, Lexer->line, mkstr("&&"),
95 | BOOLAND);
96 | }
97 | return create_token(Lexer->column, Lexer->line, mkstr("&"),
98 | LOGICALAND);
99 | }
100 | case '|':
101 | {
102 | next;
103 | if (Lexer->src[Lexer->pos] == '|')
104 | {
105 | next;
106 | return create_token(Lexer->column, Lexer->line, mkstr("||"),
107 | BOOLOR);
108 | }
109 | return create_token(Lexer->column, Lexer->line, mkstr("|"),
110 | LOGICALOR);
111 | }
112 | case '=':
113 | {
114 | next;
115 | if (Lexer->src[Lexer->pos] == '=')
116 | {
117 | next;
118 | return create_token(Lexer->column, Lexer->line, mkstr("=="),
119 | BOOLEQUAL);
120 | }
121 | return create_token(Lexer->column, Lexer->line, mkstr("="), EQUAL);
122 | }
123 | case '!':
124 | {
125 | next;
126 | if (Lexer->src[Lexer->pos] == '=')
127 | {
128 | next;
129 | return create_token(Lexer->column, Lexer->line, mkstr("!="),
130 | BOOLNOTEQUAL);
131 | }
132 | return create_token(Lexer->column, Lexer->line, mkstr("!"),
133 | EXCLAMATION);
134 | }
135 | case ',':
136 | {
137 | next;
138 | return create_token(Lexer->column, Lexer->line, mkstr(","), COMMA);
139 | }
140 | case '[':
141 | {
142 | next;
143 | return create_token(Lexer->column, Lexer->line, mkstr("["),
144 | INDEXBROPEN);
145 | }
146 | case ']':
147 | {
148 | next;
149 | return create_token(Lexer->column, Lexer->line, mkstr("]"),
150 | INDEXBROPEN);
151 | }
152 | case ';':
153 | {
154 | next;
155 | return create_token(Lexer->column, Lexer->line, mkstr(";"), SEMI);
156 | }
157 | case '-':
158 | {
159 | next;
160 | if (is_digit(Lexer->src[Lexer->pos]))
161 | {
162 | char *result;
163 | size_t start = Lexer->pos;
164 | size_t column = Lexer->column;
165 | size_t line = Lexer->line;
166 |
167 | while (is_digit(Lexer->src[Lexer->pos]))
168 | {
169 | next;
170 | }
171 | if (Lexer->src[Lexer->pos] == '.')
172 | {
173 | next;
174 | }
175 | while (is_digit(Lexer->src[Lexer->pos]))
176 | {
177 | next;
178 | }
179 | size_t len = Lexer->pos - start;
180 | result = malloc(len);
181 | result[len] = 0;
182 | Lexer->pos = start;
183 | while (is_digit(Lexer->src[Lexer->pos]))
184 | {
185 | result[Lexer->pos - start] = Lexer->src[Lexer->pos];
186 | next;
187 | }
188 | if (Lexer->src[Lexer->pos] == '.')
189 | {
190 | result[Lexer->pos - start] = '.';
191 | next;
192 | }
193 | while (is_digit(Lexer->src[Lexer->pos]))
194 | {
195 | result[Lexer->pos - start] = Lexer->src[Lexer->pos];
196 | next;
197 | }
198 | char *res2 = malloc(len + 2);
199 | memset(res2, 0, len + 2);
200 | sprintf(res2, "-%s", result);
201 | free(result);
202 | return create_token(column, line, res2, NUMBER);
203 | }
204 | if (Lexer->src[Lexer->pos] == '>')
205 | {
206 | next;
207 | return create_token(Lexer->column, Lexer->line, mkstr("->"),
208 | ARROW);
209 | }
210 | return create_token(Lexer->column, Lexer->line, mkstr("-"), MINUS);
211 | }
212 | case '+':
213 | {
214 | next;
215 | return create_token(Lexer->column, Lexer->line, mkstr("+"), PLUS);
216 | }
217 | case '/':
218 | {
219 | next;
220 | return create_token(Lexer->column, Lexer->line, mkstr("/"), DIV);
221 | }
222 | case '*':
223 | {
224 | next;
225 | if (Lexer->src[Lexer->pos] >= 'a' &&
226 | Lexer->src[Lexer->pos] <= 'z' ||
227 | Lexer->src[Lexer->pos] >= 'A' &&
228 | Lexer->src[Lexer->pos] <= 'Z' ||
229 | Lexer->src[Lexer->pos] == '_')
230 | {
231 | size_t start = Lexer->pos;
232 | size_t column = Lexer->column;
233 | size_t line = Lexer->line;
234 | while (Lexer->src[Lexer->pos] >= 'A' &&
235 | Lexer->src[Lexer->pos] <= 'Z' ||
236 | Lexer->src[Lexer->pos] >= 'a' &&
237 | Lexer->src[Lexer->pos] <= 'z' ||
238 | Lexer->src[Lexer->pos] == '_' ||
239 | is_digit(Lexer->src[Lexer->pos]))
240 | {
241 | next;
242 | }
243 | size_t len = Lexer->pos - start;
244 | char *result = malloc(len + 1);
245 | result[len] = 0;
246 | Lexer->pos = start;
247 | while (Lexer->src[Lexer->pos] >= 'A' &&
248 | Lexer->src[Lexer->pos] <= 'Z' ||
249 | Lexer->src[Lexer->pos] >= 'a' &&
250 | Lexer->src[Lexer->pos] <= 'z' ||
251 | Lexer->src[Lexer->pos] == '_' ||
252 | is_digit(Lexer->src[Lexer->pos]))
253 | {
254 | result[Lexer->pos - start] = Lexer->src[Lexer->pos];
255 | next;
256 | }
257 | return create_token(column, line, result, DEREF);
258 | }
259 | return create_token(Lexer->column, Lexer->line, mkstr("*"), MUL);
260 | }
261 | case '>':
262 | {
263 | next;
264 | if (Lexer->src[Lexer->pos] == '=')
265 | {
266 | next;
267 | return create_token(Lexer->column, Lexer->line, mkstr(">="),
268 | MOREEQUAL);
269 | }
270 | return create_token(Lexer->column, Lexer->line, mkstr(">"), MORE);
271 | }
272 | case '<':
273 | {
274 | next;
275 | if (Lexer->src[Lexer->pos] == '=')
276 | {
277 | next;
278 | return create_token(Lexer->column, Lexer->line, mkstr("<="),
279 | MOREEQUAL);
280 | }
281 | return create_token(Lexer->column, Lexer->line, mkstr("<"), MORE);
282 | }
283 | #pragma endregion
284 | #pragma region COMMENT
285 | case '#':
286 | {
287 | next;
288 | while (Lexer->src[Lexer->pos] != '\n' &&
289 | Lexer->src[Lexer->pos] != '\r' &&
290 | Lexer->src[Lexer->pos] != '#')
291 | {
292 | next;
293 | }
294 | return lex(Lexer);
295 | }
296 | #pragma endregion
297 | #pragma region WS
298 | case '\n':
299 | {
300 | size_t c = Lexer->column;
301 | size_t l = Lexer->line;
302 | ++Lexer->line;
303 | ++Lexer->pos;
304 | Lexer->column = 0;
305 | return lex(Lexer);
306 | }
307 | case ' ':
308 | case '\t':
309 | case '\r':
310 | {
311 | next;
312 | return lex(Lexer);
313 | }
314 | #pragma endregion
315 | #pragma region STRING
316 | case '"':
317 | {
318 | next;
319 | size_t start = Lexer->pos;
320 | size_t column = Lexer->column;
321 | size_t line = Lexer->line;
322 | char *value_of_string;
323 | while (Lexer->src[Lexer->pos] != '"')
324 | {
325 | next;
326 | }
327 | size_t len = Lexer->pos - start;
328 |
329 | value_of_string = malloc(len + 1);
330 | memset(value_of_string, 0, len + 1);
331 | Lexer->pos = start;
332 | while (Lexer->src[Lexer->pos] != '"')
333 | {
334 | value_of_string[Lexer->pos - start] = Lexer->src[Lexer->pos];
335 | next;
336 | }
337 | char *val = malloc(len + 3);
338 | sprintf(val, "'%s'", value_of_string);
339 | next;
340 | return create_token(column, line, val, STRING);
341 | }
342 | #pragma endregion
343 | }
344 | #pragma region ID
345 |
346 | if ((Lexer->src[Lexer->pos] >= 'A' && Lexer->src[Lexer->pos] <= 'Z') ||
347 | (Lexer->src[Lexer->pos] >= 'a' && Lexer->src[Lexer->pos] <= 'z') ||
348 | (Lexer->src[Lexer->pos] == '_'))
349 | {
350 | size_t start = Lexer->pos;
351 | size_t column = Lexer->column;
352 | size_t line = Lexer->line;
353 | while (Lexer->src[Lexer->pos] >= 'A' && Lexer->src[Lexer->pos] <= 'Z' ||
354 | Lexer->src[Lexer->pos] >= 'a' && Lexer->src[Lexer->pos] <= 'z' ||
355 | Lexer->src[Lexer->pos] == '_' ||
356 | is_digit(Lexer->src[Lexer->pos]))
357 | {
358 | next;
359 | }
360 | size_t len = Lexer->pos - start;
361 | char *result = malloc(len + 1);
362 | result[len] = 0;
363 | Lexer->pos = start;
364 | while (Lexer->src[Lexer->pos] >= 'A' && Lexer->src[Lexer->pos] <= 'Z' ||
365 | Lexer->src[Lexer->pos] >= 'a' && Lexer->src[Lexer->pos] <= 'z' ||
366 | Lexer->src[Lexer->pos] == '_' ||
367 | is_digit(Lexer->src[Lexer->pos]))
368 | {
369 | result[Lexer->pos - start] = Lexer->src[Lexer->pos];
370 | next;
371 | }
372 | if (Lexer->src[Lexer->pos] == ':')
373 | {
374 | next;
375 | return create_token(column, line, result, LABEL);
376 | }
377 | return create_token(column, line, result, ID);
378 | }
379 | #pragma endregion
380 | #pragma region NUMBER
381 | if (is_digit(Lexer->src[Lexer->pos]))
382 | {
383 | char *result;
384 | size_t start = Lexer->pos;
385 | size_t column = Lexer->column;
386 | size_t line = Lexer->line;
387 |
388 | while (is_digit(Lexer->src[Lexer->pos]))
389 | {
390 | next;
391 | }
392 | if (Lexer->src[Lexer->pos] == '.')
393 | {
394 | next;
395 | }
396 | while (is_digit(Lexer->src[Lexer->pos]))
397 | {
398 | next;
399 | }
400 | size_t len = Lexer->pos - start;
401 | result = malloc(len);
402 | result[len] = 0;
403 | Lexer->pos = start;
404 | while (is_digit(Lexer->src[Lexer->pos]))
405 | {
406 | result[Lexer->pos - start] = Lexer->src[Lexer->pos];
407 | next;
408 | }
409 | if (Lexer->src[Lexer->pos] == '.')
410 | {
411 | result[Lexer->pos - start] = '.';
412 | next;
413 | }
414 | while (is_digit(Lexer->src[Lexer->pos]))
415 | {
416 | result[Lexer->pos - start] = Lexer->src[Lexer->pos];
417 | next;
418 | }
419 | return create_token(column, line, result, NUMBER);
420 | }
421 | #pragma endregion
422 | return create_token(Lexer->column, Lexer->line, mkstr("BAD"), BAD);
423 | }
424 |
--------------------------------------------------------------------------------
/src/lexer/lexer.h:
--------------------------------------------------------------------------------
1 | #ifndef LEXER_H
2 |
3 | #define LEXER_H
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "../util.h"
11 |
12 | typedef enum
13 | {
14 | STRING,
15 | NUMBER,
16 | ID,
17 | BEGINOFBLOCK,
18 | ENDOFBLOCK,
19 | OPENBR,
20 | CLOSEBR,
21 | EQUAL,
22 | BOOLNOTEQUAL,
23 | BOOLEQUAL,
24 | EXCLAMATION,
25 | INDEXBROPEN,
26 | INDEXBRCLOSE,
27 | MORE,
28 | ARROW,
29 | LESS,
30 | MOREEQUAL,
31 | LESSEQUAL,
32 | BOOLOR,
33 | BOOLAND,
34 | LOGICALAND,
35 | LOGICALOR,
36 | XOR,
37 | PLUS,
38 | MINUS,
39 | DIV,
40 | MUL,
41 | SEMI,
42 | NL,
43 | COMMA,
44 | END_OF_FILE,
45 | BAD,
46 | NOTOKEN,
47 | REF,
48 | DEREF,
49 | LABEL,
50 | } token_type;
51 |
52 | typedef struct
53 | {
54 | uint32_t col, row;
55 | token_type type;
56 | size_t len;
57 | char *text;
58 | int on_stack;
59 | } token;
60 |
61 | #define string_version(x) (#x)
62 |
63 | #define create_token(col, row, text, type) \
64 | ((token){col, row, type, strlen(text), text})
65 |
66 | #define token_type_to_string(__type) \
67 | (((char *[]){ \
68 | "STRING", "NUMBER", "ID", "BEGINOFBLOCK", \
69 | "ENDOFBLOCK", "OPENBR", "CLOSEBR", "EQUAL", \
70 | "BOOLNOTEQUAL", "BOOLEQUAL", "EXCLAMATION", "INDEXBROPEN", \
71 | "INDEXBRCLOSE", "MORE", "ARROW", "LESS", \
72 | "MOREEQUAL", "LESSEQUAL", "BOOLOR", "BOOLAND", \
73 | "LOGICALAND", "LOGICALOR", "XOR", "PLUS", \
74 | "MINUS", "DIV", "MUL", "SEMI", \
75 | "NL", "COMMA", "END_OF_FILE", "BAD", \
76 | "NOTOKEN", "REF", "DEREF", "LABEL"})[__type])
77 |
78 | typedef struct
79 | {
80 | char *src;
81 | int line;
82 | int column;
83 | int pos;
84 | } lexer;
85 |
86 | #define next \
87 | ++Lexer->pos; \
88 | ++Lexer->column
89 |
90 | token lex(lexer *);
91 |
92 | char *read_file(char *path);
93 |
94 | char *mkstr(char *str);
95 | #endif
96 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "il/il.h"
5 | #include "lexer/lexer.h"
6 | #include "parser/parser.h"
7 | #include "typechecker/typechecker.h"
8 | #include "util.h"
9 | // if you're looking for comments...
10 | // about that...
11 |
12 | char *get_output_file(char **argv)
13 | {
14 | while (*argv)
15 | {
16 | if (!strcmp(*argv, "-o"))
17 | {
18 | return *(++argv);
19 | }
20 | ++argv;
21 | }
22 | }
23 |
24 | char *get_input_file(char **argv)
25 | {
26 | char *input = "test.lf";
27 | while (*argv)
28 | {
29 | if ((*argv)[0] != '-')
30 | {
31 | input = *argv;
32 | break;
33 | }
34 | }
35 | return input;
36 | }
37 |
38 | node *global_tree;
39 | token *global_tokens;
40 | parser *global_parser;
41 | typechecker *global_typechecker;
42 |
43 | int state = 0;
44 |
45 | enum states
46 | {
47 | LEXING,
48 | PARSING,
49 | RESTRUCTURING,
50 | TYPECHECKING,
51 | IL_CREATION,
52 | };
53 |
54 | void panic_handler(int s)
55 | {
56 | if (s == SIGSEGV)
57 | {
58 | printf("ERROR: An unkown error occurred.\n");
59 | printf("The error occured at during the '%s' stage.\n",
60 | ((char *[]){"lexing", "parsing", "tree restructuring",
61 | "typechecking", "il creation"})[state]);
62 | printf(
63 | "This error could not be resolved in any way and so the compiler "
64 | "will "
65 | "exit.\n");
66 | exit(1);
67 | }
68 | }
69 |
70 | int main(int argc, char **argv)
71 | {
72 | signal(SIGSEGV, panic_handler);
73 | ++argv;
74 | char *input_file = read_file(get_input_file(argv));
75 |
76 | lexer Lexer = (lexer){input_file, 1, 0, 0};
77 | token *Tokens = malloc(sizeof(token));
78 | size_t n_token = 1;
79 | for (;;)
80 | {
81 | token T = lex(&Lexer);
82 | printf("TOKEN(%s,%s, %d)\n", T.text,
83 | (T.type <= DEREF) ? (token_type_to_string(T.type)) : "UNK", T.type);
84 | Tokens = realloc(Tokens, n_token * sizeof(token));
85 | Tokens[n_token - 1] = T;
86 | ++n_token;
87 | if (T.type == BAD || T.type == END_OF_FILE)
88 | {
89 | break;
90 | }
91 | }
92 | ++state;
93 |
94 | free(input_file);
95 | parser *Parser = create_parser(Tokens, n_token - 1);
96 | node *root = parse(Parser);
97 | ++state;
98 |
99 | restructure_parents(root);
100 | ++state;
101 | free(Tokens);
102 |
103 | print_tree(root, 0);
104 |
105 | typechecker *Typechecker = calloc(sizeof(typechecker), 1);
106 | type_check_tree(root, Typechecker);
107 | ++state;
108 | char *il = generate_il(root, Typechecker);
109 | printf("--IL--\n\n%s\n", il);
110 | free_tree(root);
111 | free(Typechecker->functions);
112 | free(Typechecker->variables);
113 | free(Typechecker);
114 | return 0;
115 | }
116 |
--------------------------------------------------------------------------------
/src/optimizer/optimizer.h:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/parser/parser.c:
--------------------------------------------------------------------------------
1 | #include "parser.h"
2 |
3 | node *append_child_to_x(node *x, node *y)
4 | {
5 | if (!x)
6 | {
7 | x = calloc(sizeof(node), 1);
8 | }
9 | if (!x->children)
10 | {
11 | x->children = malloc(sizeof(node *));
12 | x->children[0] = y;
13 | x->n_child = 1;
14 | return x;
15 | }
16 | x->children = realloc(x->children, sizeof(node *) * (x->n_child + 1));
17 | x->children[x->n_child] = y;
18 | ++x->n_child;
19 | return x;
20 | }
21 |
22 | #define append_child(x, y) x = append_child_to_x(x, y)
23 |
24 | void put_error(char *msg, node *Node, token t)
25 | {
26 | if (Node)
27 | printf("ERROR: %s LN: %d COL: %d\n", msg, Node->node_token.row,
28 | Node->node_token.col);
29 | else
30 | printf("ERROR: %s LN: %d COL: %d\n", msg, t.row, t.col);
31 | free(msg);
32 | exit(-1);
33 | }
34 |
35 | bool expect(token_type type, parser *Parser, bool error)
36 | {
37 | if (Parser->tokens[Parser->pos + 1].type == type)
38 | {
39 | return true;
40 | }
41 | if (error)
42 | {
43 | char *msg = "Expected '%s' but got '%s'.";
44 | char *buffer = malloc(1024);
45 | sprintf(buffer, msg, token_type_to_string(type),
46 | token_type_to_string(Parser->tokens[Parser->pos + 1].type));
47 | put_error(buffer, 0, Parser->tokens[Parser->pos + 1]);
48 | // exits the program so no need to free.
49 | }
50 | return false;
51 | }
52 |
53 | node *create_arbitrary_node(node_type type, node *parent)
54 | {
55 | token node_token =
56 | create_token(0, 0, mkstr(node_type_to_string(type)), NOTOKEN);
57 | node_token.on_stack = true;
58 | node *n = malloc(sizeof(node));
59 | n->type = type;
60 | n->node_token = node_token;
61 | n->parent = parent;
62 | n->children = malloc(sizeof(void *));
63 | n->n_child = 0;
64 | return n;
65 | }
66 |
67 | node *create_node(node_type type, token node_token, node *parent)
68 | {
69 | node *n = malloc(sizeof(node));
70 | n->type = type;
71 | n->node_token = node_token;
72 | n->parent = parent;
73 | n->children = malloc(sizeof(void *));
74 | n->n_child = 0;
75 | return n;
76 | }
77 | parser *create_parser(token *tokens, size_t n_token)
78 | {
79 | parser *Parser = malloc(sizeof(parser));
80 | token t = create_token(0, 0, mkstr("PROGRAM"), NOTOKEN);
81 |
82 | t.on_stack = 1;
83 | Parser->root = create_node(PROGRAM, t, 0);
84 | Parser->current_parent = Parser->root;
85 | Parser->pos = 0;
86 | Parser->tokens = tokens;
87 | Parser->n_token = n_token;
88 | return Parser;
89 | }
90 |
91 | #define expect_err(x) \
92 | expect(x, Parser, true); \
93 | ++Parser->pos
94 | #define expect_err_no_inc(x) expect(x, Parser, true)
95 |
96 | #define expect_no_err(x) expect(x, Parser, false)
97 |
98 | #define conditional_token(x) \
99 | !strcmp("if", x.text) || !strcmp("else", x.text) || \
100 | !strcmp("while", x.text) || !strcmp("for", x.text)
101 |
102 | bool f_is_type(int type, parser *Parser, bool err)
103 | {
104 | if (Parser->tokens[Parser->pos].type == type)
105 | {
106 | return true;
107 | }
108 | if (err)
109 | {
110 | char *msg = "Expected '%s' but got '%s'.";
111 | char *buffer = malloc(1024);
112 | sprintf(buffer, msg, token_type_to_string(type),
113 | token_type_to_string(Parser->tokens[Parser->pos + 1].type));
114 | put_error(buffer, 0, Parser->tokens[Parser->pos]);
115 | }
116 | return false;
117 | }
118 | #define is_type(x) (f_is_type(x, Parser, false))
119 | #define is_type_err(x) (f_is_type(x, Parser, true))
120 |
121 | node *parse_primary(parser *Parser);
122 |
123 | #define type_token(x) \
124 | ((!strcmp(x.text, "ptr8") || !strcmp(x.text, "ptr") || \
125 | !strcmp(x.text, "ptr16") || !strcmp(x.text, "ptr32") || \
126 | !strcmp(x.text, "struct") || !strcmp(x.text, "i32") || \
127 | !strcmp(x.text, "i16") || !strcmp(x.text, "i8")) || \
128 | (!strcmp(x.text, "u32") || !strcmp(x.text, "u16") || \
129 | !strcmp(x.text, "u8")))
130 |
131 | node *parse_expression(parser *Parser);
132 | node *parse_assignment(parser *Parser, node *parent)
133 | {
134 | node *id = create_node(TOKENNODE, Parser->tokens[Parser->pos], parent);
135 | if (!expect_no_err(EQUAL))
136 | {
137 | return id;
138 | }
139 |
140 | // safe to assume its an actual assignment
141 | expect_err(EQUAL);
142 | ++Parser->pos; // skip the equal
143 | node *next = parse_primary(Parser);
144 | node *assign = create_arbitrary_node(ASSIGNMENT, parent);
145 | append_child(assign, id);
146 | append_child(assign, next);
147 | --Parser->pos; // go back or weird errors happen??
148 | return assign;
149 | }
150 | node *parse_function_call(parser *Parser)
151 | {
152 | if (!strcmp("extern", Parser->tokens[Parser->pos].text))
153 | {
154 | expect_err(OPENBR);
155 | expect_err(STRING);
156 | node *arb = create_arbitrary_node(EXTERN, 0);
157 | node *tok = create_node(TOKENNODE, Parser->tokens[Parser->pos], arb);
158 | append_child(arb, tok);
159 | expect_err(CLOSEBR);
160 | return arb;
161 | }
162 | if (!strcmp("asm", Parser->tokens[Parser->pos].text))
163 | {
164 | expect_err(OPENBR);
165 | expect_err(STRING);
166 | node *arb = create_arbitrary_node(ASM, 0);
167 | node *tok = create_node(TOKENNODE, Parser->tokens[Parser->pos], arb);
168 | append_child(arb, tok);
169 | expect_err(CLOSEBR);
170 | return arb;
171 | }
172 | node *id_node = create_node(FUNCTION_CALL, Parser->tokens[Parser->pos],
173 | Parser->current_parent);
174 | expect_err(OPENBR);
175 |
176 | ++Parser->pos;
177 | if (!is_type(CLOSEBR))
178 | {
179 | while (!is_type(CLOSEBR))
180 | {
181 | if (is_type(COMMA)) ++Parser->pos;
182 | node *next = parse_primary(Parser);
183 | append_child(id_node, next);
184 | }
185 | }
186 | return id_node;
187 | }
188 | node *parse_id(parser *Parser)
189 | {
190 | if (!strcmp("return", Parser->tokens[Parser->pos].text))
191 | {
192 | expect_err(ID);
193 | return create_node(RETURN, Parser->tokens[Parser->pos++], 0);
194 | }
195 | if (!strcmp("goto", Parser->tokens[Parser->pos].text))
196 | {
197 | expect_err(ID);
198 | return create_node(GOTO, Parser->tokens[Parser->pos++], 0);
199 | }
200 | if (!expect_no_err(OPENBR) && !type_token(Parser->tokens[Parser->pos]))
201 | {
202 | node *id = create_node(TOKENNODE, Parser->tokens[Parser->pos], 0);
203 | node *assign = parse_assignment(Parser, 0);
204 | node *arb_expr = create_arbitrary_node(BASICEXPRESSION, 0);
205 | if (assign->type != TOKENNODE)
206 | {
207 | assign->parent = arb_expr;
208 | append_child(arb_expr, assign);
209 | return arb_expr;
210 | }
211 | append_child(arb_expr, id);
212 | return arb_expr;
213 | }
214 | else if (type_token(Parser->tokens[Parser->pos]))
215 | {
216 | node *type_node = create_node(TYPE, Parser->tokens[Parser->pos], 0);
217 | expect_err(ID);
218 | if (!strcmp(Parser->tokens[Parser->pos - 1].text, "struct"))
219 | {
220 | // hopefully not a struct definition. (while we're still building
221 | // out the parser)
222 | type_node = create_node(
223 | TYPE, Parser->tokens[Parser->pos + 1],
224 | 0); // we just assume it isnt just for testing purposes.
225 | expect_err(ID);
226 | }
227 | if (!expect_no_err(OPENBR))
228 | {
229 | node *var_decl =
230 | create_arbitrary_node(VARDECL, Parser->current_parent);
231 | node *id =
232 | create_node(TOKENNODE, Parser->tokens[Parser->pos], var_decl);
233 | type_node->parent = var_decl;
234 | node *assignment = parse_assignment(Parser, var_decl);
235 | if (assignment->type == TOKENNODE)
236 | {
237 | // its not an assignment
238 | append_child(var_decl, type_node);
239 | append_child(var_decl, id);
240 | return var_decl;
241 | }
242 | // safely assume its an assignment
243 | append_child(var_decl, type_node);
244 | append_child(var_decl, assignment);
245 | return var_decl;
246 | }
247 |
248 | // safe to assume its a function declaration.
249 | // which is a problem becuase that should've been handled :((((
250 | }
251 | else if (expect_no_err(OPENBR))
252 | {
253 | return parse_function_call(Parser);
254 | }
255 | }
256 |
257 | node *parse_basic_expression(parser *Parser)
258 | {
259 | if (is_type(ID))
260 | {
261 | node *expr = parse_id(Parser);
262 | return expr;
263 | }
264 | node *arb_expr = create_arbitrary_node(BASICEXPRESSION, 0);
265 | node *expr = create_node(TOKENNODE, Parser->tokens[Parser->pos], arb_expr);
266 | append_child(arb_expr, expr);
267 | return arb_expr;
268 | }
269 |
270 | node *parse_factor(parser *Parser)
271 | {
272 | node *left = parse_basic_expression(Parser);
273 |
274 | while (expect_no_err(DIV) || expect_no_err(MUL) ||
275 | expect_no_err(BOOLEQUAL) || expect_no_err(BOOLNOTEQUAL) ||
276 | expect_no_err(LESS) || expect_no_err(MORE) ||
277 | expect_no_err(MOREEQUAL) || expect_no_err(LESSEQUAL))
278 | {
279 | ++Parser->pos;
280 | node *operator=
281 | create_node(TOKENNODE, Parser->tokens[Parser->pos], left);
282 | ++Parser->pos;
283 | node *right = parse_basic_expression(Parser);
284 | append_child(operator, left);
285 | append_child(operator, right);
286 | left->parent = operator;
287 | right->parent = operator;
288 | left = operator;
289 | }
290 |
291 | return left;
292 | }
293 | node *parse_primary(parser *Parser)
294 | {
295 | node *left = parse_factor(Parser);
296 | if (left->type == BLOCK)
297 | {
298 | Parser->current_parent = left;
299 | if (expect_no_err(ENDOFBLOCK))
300 | {
301 | return left;
302 | }
303 | }
304 | while (expect_no_err(PLUS) || expect_no_err(MINUS) ||
305 | expect_no_err(BOOLAND) || expect_no_err(BOOLOR))
306 | {
307 | ++Parser->pos;
308 | node *operator=
309 | create_node(TOKENNODE, Parser->tokens[Parser->pos], left);
310 | ++Parser->pos;
311 | node *right = parse_factor(Parser);
312 | left->parent = operator;
313 | right->parent = operator;
314 | append_child(operator, left);
315 | append_child(operator, right);
316 | left = operator;
317 | }
318 | if (expect_no_err(SEMI))
319 | {
320 | ++Parser->pos;
321 | }
322 | if (left->n_child != 0 && (left->type == TOKENNODE))
323 | {
324 | node *binexpr_node = create_arbitrary_node(BINEXPR, 0);
325 | left->parent = binexpr_node;
326 | append_child(binexpr_node, left);
327 | ++Parser->pos;
328 | return binexpr_node;
329 | }
330 | ++Parser->pos;
331 | return left;
332 | }
333 |
334 | node *parse_conditional(parser *Parser)
335 | {
336 | node *cond = create_arbitrary_node(CONDITIONAL, Parser->current_parent);
337 | // Parser->current_parent = cond;
338 | if (!strcmp("if", Parser->tokens[Parser->pos].text))
339 | {
340 | append_child(Parser->current_parent, cond);
341 | node *arb_if = create_arbitrary_node(IF, cond);
342 | expect_err(OPENBR);
343 | ++Parser->pos;
344 | node *expr = parse_primary(Parser);
345 | ++Parser->pos;
346 | // expect_err( CLOSEBR );
347 | expr->parent = arb_if;
348 | append_child(cond, arb_if);
349 | append_child(arb_if, expr);
350 | Parser->current_parent = arb_if;
351 |
352 | return parse(Parser);
353 | }
354 | if (!strcmp("while", Parser->tokens[Parser->pos].text))
355 | {
356 | append_child(Parser->current_parent, cond);
357 | node *arb_while = create_arbitrary_node(WHILE, cond);
358 | expect_err(OPENBR);
359 | ++Parser->pos;
360 | node *expr = parse_primary(Parser);
361 | ++Parser->pos;
362 | // expect_err( CLOSEBR );
363 | expr->parent = arb_while;
364 | append_child(cond, arb_while);
365 | append_child(arb_while, expr);
366 | Parser->current_parent = arb_while;
367 |
368 | return parse(Parser);
369 | }
370 | if (!strcmp("else", Parser->tokens[Parser->pos].text))
371 | {
372 | if (expect_no_err(BEGINOFBLOCK))
373 | {
374 | // normal else
375 | if (Parser->current_parent->n_child &&
376 | Parser->current_parent
377 | ->children[Parser->current_parent->n_child - 1]
378 | ->type == CONDITIONAL)
379 | {
380 | node *arb_else = create_arbitrary_node(ELSE, cond);
381 | ++Parser->pos;
382 | append_child(
383 | Parser->current_parent
384 | ->children[Parser->current_parent->n_child - 1],
385 | arb_else);
386 | Parser->current_parent = arb_else;
387 | return parse(Parser);
388 | }
389 | put_error("Floating else statement.", 0,
390 | Parser->tokens[Parser->pos]);
391 | }
392 | // the comment under this explains the current state.
393 | }
394 | // I'll do something when I'm not lazy, for now just a seg fault
395 | }
396 | node *parse_func(parser *Parser)
397 | {
398 | node *type_node = create_node(TYPE, Parser->tokens[Parser->pos - 1], 0);
399 | expect_err(OPENBR);
400 | node *func = create_arbitrary_node(FUNCTION, 0);
401 | node *id = create_node(TOKENNODE, Parser->tokens[Parser->pos - 1], func);
402 | append_child(func, type_node);
403 | append_child(func, id);
404 | ++Parser->pos;
405 | while (!is_type(CLOSEBR)) // eg i32 b( something ) instead of i32 b()
406 | {
407 | if (is_type(COMMA)) ++Parser->pos;
408 | node *next = parse_primary(Parser);
409 | append_child(func, next);
410 | }
411 | --Parser->pos;
412 | expect_err(CLOSEBR);
413 | ++Parser->pos;
414 | append_child(Parser->root, func);
415 | Parser->current_parent = func;
416 | return parse(Parser);
417 | }
418 | node *parse_full_id(parser *Parser)
419 | {
420 | node *arb_expr = create_arbitrary_node(EXPRESSION, Parser->current_parent);
421 | if (conditional_token(Parser->tokens[Parser->pos]))
422 | {
423 | return parse_conditional(Parser);
424 | }
425 | if (type_token(Parser->tokens[Parser->pos]))
426 | {
427 | expect_err(ID);
428 | // make sure its not a var decl
429 | if (!expect_no_err(OPENBR))
430 | {
431 | --Parser->pos;
432 | node *expr = parse_primary(Parser);
433 | expr->parent = arb_expr;
434 | append_child(arb_expr, expr);
435 | append_child(Parser->current_parent, arb_expr);
436 | return parse(Parser);
437 | }
438 | return parse_func(Parser);
439 | }
440 | node *expr = parse_primary(Parser);
441 | expr->parent = arb_expr;
442 | append_child(arb_expr, expr);
443 | append_child(Parser->current_parent, arb_expr);
444 | return parse(Parser);
445 | }
446 | node *parse_expression(parser *Parser)
447 | {
448 | node *arb_expr = create_arbitrary_node(EXPRESSION, Parser->current_parent);
449 | switch (Parser->tokens[Parser->pos].type)
450 | {
451 | case LABEL:
452 | {
453 | node *parent = Parser->current_parent;
454 | node *n =
455 | create_node(LABEL_NODE, Parser->tokens[Parser->pos], parent);
456 | append_child(parent, n);
457 | ++Parser->pos;
458 | return parse(Parser);
459 | }
460 | case DEREF:
461 | {
462 | node *parent = Parser->current_parent;
463 | node *id =
464 | create_node(TOKENNODE, Parser->tokens[Parser->pos], parent);
465 | if (!expect_no_err(EQUAL))
466 | {
467 | return id;
468 | }
469 | // safe to assume its an actual assignment
470 | expect_err(EQUAL);
471 | ++Parser->pos; // skip the equal
472 | node *next = parse_primary(Parser);
473 | node *assign = create_arbitrary_node(ASSIGNMENT, parent);
474 | append_child(assign, id);
475 | append_child(assign, next);
476 | --Parser->pos; // go back or weird errors happen??
477 | append_child(Parser->current_parent, assign);
478 |
479 | return parse(Parser);
480 | }
481 | case ID:
482 | {
483 | return parse_full_id(Parser);
484 | }
485 | case NUMBER:
486 | {
487 | node *expr = parse_primary(Parser);
488 | expr->parent = arb_expr;
489 | append_child(arb_expr, expr);
490 | append_child(Parser->current_parent, arb_expr);
491 | return parse(Parser);
492 | }
493 | case SEMI:
494 | {
495 | ++Parser->pos;
496 | return parse(Parser);
497 | }
498 | case BEGINOFBLOCK:
499 | {
500 | ++Parser->pos;
501 | node *block = create_arbitrary_node(BLOCK, Parser->current_parent);
502 | append_child(Parser->current_parent, block);
503 | Parser->current_parent = block;
504 | return parse(Parser);
505 | }
506 | case ENDOFBLOCK:
507 | {
508 | ++Parser->pos;
509 | node *p = Parser->current_parent;
510 | while (p && p->parent && p->type != BLOCK &&
511 | p->type != PROGRAM) //( p && p->parent && p->type != PROGRAM
512 | //&& !( p->type == BLOCK && p->type !=
513 | // Parser->current_parent ) )
514 | {
515 | p = p->parent;
516 | }
517 | Parser->current_parent = p;
518 | return parse(Parser);
519 | }
520 | case COMMA:
521 | {
522 | ++Parser->pos;
523 | return parse(Parser);
524 | }
525 | case END_OF_FILE:
526 | {
527 | return Parser->root;
528 | }
529 | default:
530 | {
531 | char *msg = "Unexpected token '%s'.";
532 | char *buffer = malloc(1024);
533 | sprintf(buffer, msg, Parser->tokens[Parser->pos].text);
534 | put_error(buffer, 0, Parser->tokens[Parser->pos + 1]);
535 | }
536 | }
537 | }
538 |
539 | node *parse(parser *Parser)
540 | {
541 | if (Parser->pos > Parser->n_token)
542 | {
543 | return Parser->root;
544 | }
545 | return parse_expression(Parser);
546 | }
547 |
548 | void print_tree(node *n, int indent)
549 | {
550 | print_n_times(" ", indent);
551 | printf("\n", n->node_token.text,
552 | node_type_to_string(n->type));
553 | if (n->n_child > 0)
554 | {
555 | print_n_times(" ", indent);
556 | printf("{\n");
557 | }
558 | ++indent;
559 | for (size_t i = 0; i < n->n_child; ++i)
560 | {
561 | print_tree(n->children[i], indent);
562 | }
563 | if (n->n_child > 0)
564 | {
565 | print_n_times(" ", indent - 1);
566 | printf("}\n");
567 | }
568 | }
569 |
570 | void free_tree(node *n)
571 | {
572 | for (size_t i = 0; i < n->n_child; ++i)
573 | {
574 | free_tree(n->children[i]);
575 | }
576 | free(n);
577 | }
578 |
--------------------------------------------------------------------------------
/src/parser/parser.h:
--------------------------------------------------------------------------------
1 | #ifndef PARSER_H
2 |
3 | #define PARSER_H
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "../lexer/lexer.h"
11 | #include "../util.h"
12 | #define node_type_to_string(x) \
13 | (((char *[]){ \
14 | "PROGRAM", \
15 | "FUNCTION", \
16 | "TYPE", \
17 | "TOKEN_NODE", \
18 | "BLOCK", \
19 | "NORMALBLOCK", \
20 | "ARROWBLOCK", \
21 | "EXTERN", \
22 | "ASM", \
23 | "BASICEXPRESSION", \
24 | "EXPRESSION", \
25 | "BINEXPR", \
26 | "FUNCTION_CALL", \
27 | "VARDECL", \
28 | "ASSIGNMENT", \
29 | "CONDITIONAL", \
30 | "IF", \
31 | "WHILE", \
32 | "ELSE", \
33 | "REFERENCE", \
34 | "LABEL", \
35 | "GOTO", \
36 | "RETURN", \
37 | })[x])
38 | #undef next
39 | typedef enum
40 | {
41 | PROGRAM,
42 | FUNCTION,
43 | TYPE,
44 | TOKENNODE,
45 | BLOCK,
46 | NORMALBLOCK,
47 | ARROW_BLOCK,
48 | EXTERN,
49 | ASM,
50 | BASICEXPRESSION,
51 | EXPRESSION,
52 | BINEXPR,
53 | FUNCTION_CALL,
54 | VARDECL,
55 | ASSIGNMENT,
56 | CONDITIONAL,
57 | IF,
58 | WHILE,
59 | ELSE,
60 | REFERENCE,
61 | LABEL_NODE,
62 | GOTO,
63 | RETURN,
64 | } node_type;
65 |
66 | typedef struct node
67 | {
68 | node_type type;
69 | token node_token;
70 | struct node **children;
71 | size_t n_child;
72 | struct node *parent;
73 | } node;
74 |
75 | typedef struct
76 | {
77 | size_t n_token;
78 | token *tokens;
79 | size_t pos;
80 | node *root;
81 | node *current_parent;
82 | } parser;
83 |
84 | parser *create_parser(token *tokens, size_t n_token);
85 |
86 | node *parse(parser *Parser);
87 | node *create_node(node_type type, token node_token, node *parent);
88 | node *create_arbitrary_node(node_type type, node *parent);
89 | void print_tree(node *n, int indent);
90 | void put_error(char *msg, node *Node, token t);
91 | #define append_child(x, y) x = append_child_to_x(x, y)
92 | node *append_child_to_x(node *x, node *y);
93 |
94 | void free_tree(node *n);
95 |
96 | #endif
97 |
--------------------------------------------------------------------------------
/src/typechecker/typechecker.c:
--------------------------------------------------------------------------------
1 | #include "typechecker.h"
2 |
3 | #include
4 | #include
5 | #include
6 | bool is_node(node *t, node_type type)
7 | {
8 | assert((t && "T should exist in this situation."));
9 | return t->type == type;
10 | }
11 |
12 | void restructure_parents(node *tree)
13 | {
14 | if (tree->n_child == 0)
15 | {
16 | return;
17 | }
18 | for (size_t i = 0; i < tree->n_child; ++i)
19 | {
20 | tree->children[i]->parent = tree;
21 | restructure_parents(tree->children[i]);
22 | }
23 | }
24 |
25 | bool has_child_recursive(node *check, node_type type)
26 | {
27 | if (is_node(check, type))
28 | {
29 | return true;
30 | }
31 | for (size_t i = 0; i < check->n_child; ++i)
32 | {
33 | bool is = has_child_recursive(check->children[i], type);
34 | if (is)
35 | {
36 | return is;
37 | }
38 | }
39 | return false;
40 | }
41 | // gets first instance...
42 | node *get_child_recursive(node *check, node_type type)
43 | {
44 | if (is_node(check, type))
45 | {
46 | return check;
47 | }
48 | for (size_t i = 0; i < check->n_child; ++i)
49 | {
50 | node *is = get_child_recursive(check->children[i], type);
51 | if (is)
52 | {
53 | return is;
54 | }
55 | }
56 | return 0;
57 | }
58 |
59 | node *get_parent(node *check, node_type type)
60 | {
61 | node *p = check;
62 | while (p)
63 | {
64 | if (p->type == type)
65 | {
66 | return p;
67 | }
68 | p = p->parent;
69 | }
70 | return 0;
71 | }
72 |
73 | function *get_function(typechecker *type_checker, char *title)
74 | {
75 | for (size_t i = 0; i != type_checker->n_func; ++i)
76 | {
77 | if (!strcmp(title, type_checker->functions[i].title))
78 | {
79 | return type_checker->functions + i;
80 | }
81 | }
82 | return 0;
83 | }
84 |
85 | variable *get_var(typechecker *type_checker, char *title, size_t scope,
86 | function *func)
87 | {
88 | for (size_t i = 0; i != type_checker->n_var; ++i)
89 | {
90 | if (!strcmp(title, type_checker->variables[i].title) &&
91 | type_checker->variables[i].scope == scope &&
92 | type_checker->variables[i].func->title == func->title)
93 | {
94 | return &type_checker->variables[i];
95 | }
96 | }
97 | return 0;
98 | }
99 | // big mac of a function name right there.
100 | void put_error_incompatible_types_assignment(char *type_a, char *type_b,
101 | node *n)
102 | {
103 | // dont need to free since put_error kills the program
104 | char *buffer = malloc(1024);
105 | sprintf(buffer,
106 | "Incompatible types used in an assigmnent Type '%s' is assigned to "
107 | "Type '%s'",
108 | type_a, type_b);
109 | put_error(buffer, 0, n->node_token);
110 | }
111 |
112 | bool starts_with(char *a, char *b)
113 | {
114 | if (!a || !b)
115 | {
116 | return false;
117 | }
118 | if (!strcmp(a, b))
119 | {
120 | return true;
121 | }
122 | if (strlen(a) < strlen(b))
123 | {
124 | return false;
125 | }
126 | size_t lenb = strlen(b);
127 | char *start_of_a = a;
128 | while (*a)
129 | {
130 | if (*a != *b)
131 | {
132 | return (a - start_of_a == lenb);
133 | }
134 | ++a;
135 | ++b;
136 | }
137 | return false;
138 | }
139 |
140 | void put_error_incompatible_operation(char *operation, char *a, char *b,
141 | node *n)
142 | {
143 | char *buffer = malloc(1024);
144 | sprintf(buffer, "Cannot do operation '%s' on type '%s' with '%s'.",
145 | operation, a, b);
146 | put_error(buffer, 0, n->node_token);
147 | }
148 | // put error frees the string so it gotta be on the heap :(
149 |
150 | node *eval(node *x, node *parent);
151 |
152 | char *get_type_recursive(typechecker *type_checker, node *expr)
153 | {
154 | if (expr->type == BINEXPR)
155 | {
156 | if (expr->children[0]->node_token.text[0] == '=')
157 | {
158 | return mkstr("bool");
159 | }
160 | }
161 | if (expr->type == BASICEXPRESSION)
162 | {
163 | if (expr->children[0]->node_token.type == ID)
164 | {
165 | node *f = get_parent(expr, FUNCTION);
166 | function *func =
167 | get_function(type_checker, f->children[1]->node_token.text);
168 | variable *v =
169 | get_var(type_checker, expr->children[0]->node_token.text,
170 | type_checker->scope, func);
171 | if (!v)
172 | {
173 | char *buffer = malloc(1024);
174 | sprintf(buffer, "Variable '%s' doesnt exist.",
175 | expr->children[0]->node_token.text);
176 | put_error(buffer, 0, expr->children[0]->node_token);
177 | }
178 | return v->type;
179 | }
180 | if (expr->children[0]->node_token.type == DEREF)
181 | {
182 | node *f = get_parent(expr, FUNCTION);
183 | function *func =
184 | get_function(type_checker, f->children[1]->node_token.text);
185 | variable *v =
186 | get_var(type_checker, expr->children[0]->node_token.text,
187 | type_checker->scope, func);
188 | if (!v)
189 | {
190 | char *buffer = malloc(1024);
191 | sprintf(buffer, "Variable '%s' doesnt exist.",
192 | expr->children[0]->node_token.text);
193 | put_error(buffer, 0, expr->children[0]->node_token);
194 | }
195 | if (!v->pointing_to)
196 | {
197 | char *buffer = malloc(1024);
198 | sprintf(buffer,
199 | "Variable '%s' is not a pointer and cannot be "
200 | "dereferenced.",
201 | expr->children[0]->node_token.text);
202 | put_error(buffer, 0, expr->children[0]->node_token);
203 | }
204 | return v->pointing_to->type;
205 | }
206 | if (expr->children[0]->node_token.type == NUMBER)
207 | {
208 | return mkstr("i32?"); // question mark denotes literal
209 | }
210 | if (expr->children[0]->node_token.type == STRING)
211 | {
212 | if (strlen(expr->children[0]->node_token.text) == 1)
213 | {
214 | return mkstr("u8?");
215 | }
216 | return mkstr("ptr8");
217 | }
218 | }
219 | }
220 |
221 | node *eval(node *x, node *parent)
222 | {
223 | if (x->type == BASICEXPRESSION)
224 | {
225 | return x;
226 | }
227 | switch (x->type)
228 | {
229 | case BINEXPR:
230 | {
231 | node *op = x->children[0];
232 | node *left = op->children[0];
233 | node *right = op->children[1];
234 | if (!has_child_recursive(x, BASICEXPRESSION) &&
235 | left->type != BASICEXPRESSION ||
236 | right->type != BASICEXPRESSION)
237 | {
238 | return x;
239 | }
240 | if (left->type != BASICEXPRESSION)
241 | {
242 | left = eval(left, op);
243 | }
244 | if (right->type != BASICEXPRESSION)
245 | {
246 | right = eval(right, op);
247 | }
248 | left = left->children[0];
249 | right = right->children[0];
250 | if (left->node_token.type == ID || right->node_token.type == ID)
251 | {
252 | return x;
253 | }
254 | switch (op->node_token.text[0])
255 | {
256 | case '+':
257 | {
258 | if (left->node_token.type == NUMBER &&
259 | right->node_token.type == NUMBER)
260 | {
261 | int value = atoi(left->node_token.text) +
262 | atoi(right->node_token.text);
263 | char *buf = malloc(32);
264 | sprintf(buf, "%d", value);
265 | node *x =
266 | create_arbitrary_node(BASICEXPRESSION, parent);
267 | node *n = create_node(
268 | TOKENNODE,
269 | create_token(left->node_token.col,
270 | left->node_token.row, buf, NUMBER),
271 | x);
272 | append_child(x, n);
273 | return x;
274 | }
275 | put_error_incompatible_operation(
276 | "+", token_type_to_string(left->node_token.type),
277 | token_type_to_string(right->node_token.type), right);
278 | }
279 | break;
280 | case '-':
281 | {
282 | if (left->node_token.type == NUMBER &&
283 | right->node_token.type == NUMBER)
284 | {
285 | int value = atoi(left->node_token.text) -
286 | atoi(right->node_token.text);
287 | char *buf = malloc(32);
288 | sprintf(buf, "%d", value);
289 | node *x =
290 | create_arbitrary_node(BASICEXPRESSION, parent);
291 | node *n = create_node(
292 | TOKENNODE,
293 | create_token(left->node_token.col,
294 | left->node_token.row, buf, NUMBER),
295 | x);
296 | append_child(x, n);
297 | return x;
298 | }
299 | put_error_incompatible_operation(
300 | "-", token_type_to_string(left->node_token.type),
301 | token_type_to_string(right->node_token.type), right);
302 | }
303 | break;
304 | case '/':
305 | {
306 | if (left->node_token.type == NUMBER &&
307 | right->node_token.type == NUMBER)
308 | {
309 | if (atoi(right->node_token.text) == 0)
310 | {
311 | put_error(mkstr("Attempt to divide by zero."), 0,
312 | right->node_token);
313 | }
314 | int value = atoi(left->node_token.text) /
315 | atoi(right->node_token.text);
316 | char *buf = malloc(32);
317 | sprintf(buf, "%d", value);
318 | node *x =
319 | create_arbitrary_node(BASICEXPRESSION, parent);
320 | node *n = create_node(
321 | TOKENNODE,
322 | create_token(left->node_token.col,
323 | left->node_token.row, buf, NUMBER),
324 | x);
325 | append_child(x, n);
326 | return x;
327 | }
328 | put_error_incompatible_operation(
329 | "/", token_type_to_string(left->node_token.type),
330 | token_type_to_string(right->node_token.type), right);
331 | }
332 | case '*':
333 | {
334 | if (left->node_token.type == NUMBER &&
335 | right->node_token.type == NUMBER)
336 | {
337 | int value = atoi(left->node_token.text) *
338 | atoi(right->node_token.text);
339 | char *buf = malloc(32);
340 | sprintf(buf, "%d", value);
341 | node *x =
342 | create_arbitrary_node(BASICEXPRESSION, parent);
343 | node *n = create_node(
344 | TOKENNODE,
345 | create_token(left->node_token.col,
346 | left->node_token.row, buf, NUMBER),
347 | x);
348 | append_child(x, n);
349 | return x;
350 | }
351 | put_error_incompatible_operation(
352 | "*", token_type_to_string(left->node_token.type),
353 | token_type_to_string(right->node_token.type), right);
354 | }
355 | case '=':
356 | {
357 | if (left->node_token.type == STRING &&
358 | right->node_token.type == STRING)
359 | {
360 | char *buf = malloc(32);
361 | sprintf(buf, "%d",
362 | !strcmp(left->node_token.text,
363 | right->node_token.text));
364 | node *x =
365 | create_arbitrary_node(BASICEXPRESSION, parent);
366 | node *n = create_node(
367 | TOKENNODE,
368 | create_token(left->node_token.col,
369 | left->node_token.row, buf, NUMBER),
370 | x);
371 | append_child(x, n);
372 | return x;
373 | }
374 | if (left->node_token.type == NUMBER &&
375 | right->node_token.type == NUMBER)
376 | {
377 | int value = atoi(left->node_token.text) ==
378 | atoi(right->node_token.text);
379 | char *buf = malloc(32);
380 | sprintf(buf, "%d", value);
381 | node *x =
382 | create_arbitrary_node(BASICEXPRESSION, parent);
383 | node *n = create_node(
384 | TOKENNODE,
385 | create_token(left->node_token.col,
386 | left->node_token.row, buf, NUMBER),
387 | x);
388 | append_child(x, n);
389 | return x;
390 | }
391 | put_error_incompatible_operation(
392 | "==", token_type_to_string(left->node_token.type),
393 | token_type_to_string(right->node_token.type), right);
394 | }
395 | }
396 | }
397 | default:
398 | return 0;
399 | }
400 | }
401 |
402 | bool type_check_tree(node *current, typechecker *type_checker)
403 | {
404 | start:
405 | if (!current)
406 | {
407 | return true;
408 | }
409 | switch (current->type)
410 | {
411 | case RETURN:
412 | {
413 | node *func_parent = get_parent(current, FUNCTION)->children[1];
414 | variable *v = get_var(
415 | type_checker, current->node_token.text, type_checker->scope,
416 | get_function(type_checker, func_parent->node_token.text));
417 | if (!v)
418 | {
419 | char *buffer = malloc(1024);
420 | sprintf(buffer, "Variable '%s' does not exist.\n",
421 | current->node_token.text);
422 | }
423 | if (strcmp(v->type,
424 | get_function(type_checker, func_parent->node_token.text)
425 | ->type))
426 | {
427 | char *buffer = malloc(1024);
428 | sprintf(buffer,
429 | "Function '%s' expects a return type of '%s' but was "
430 | "given a '%s'.",
431 | func_parent->node_token.text,
432 | get_function(type_checker, func_parent->node_token.text)
433 | ->type,
434 | v->type);
435 | }
436 | }
437 | case LABEL_NODE:
438 | {
439 | bool found = false;
440 | for (size_t i = 0; i < type_checker->n_label; ++i)
441 | {
442 | if (!strcmp(type_checker->labels[i], current->node_token.text))
443 | {
444 | found = true;
445 | }
446 | }
447 | if (found)
448 | {
449 | char *buffer = malloc(1024);
450 | sprintf(buffer, "Label '%s' already exists.",
451 | current->node_token.text);
452 | put_error(buffer, 0, current->node_token);
453 | }
454 | type_checker->labels =
455 | realloc(type_checker->labels,
456 | (++type_checker->n_label) * sizeof(char *));
457 | type_checker->labels[type_checker->n_label - 1] =
458 | current->node_token.text;
459 | }
460 | break;
461 | case GOTO:
462 | {
463 | bool found = false;
464 | for (size_t i = 0; i < type_checker->n_label; ++i)
465 | {
466 | if (!strcmp(type_checker->labels[i], current->node_token.text))
467 | {
468 | found = true;
469 | }
470 | }
471 | if (!found)
472 | {
473 | char *buffer = malloc(1024);
474 | sprintf(buffer, "Label '%s' doesn't exist.",
475 | current->node_token.text);
476 | put_error(buffer, 0, current->node_token);
477 | }
478 | }
479 | break;
480 | case BINEXPR:
481 | {
482 | current = eval(current, current->parent);
483 | if (current->type == BINEXPR)
484 | {
485 | goto end;
486 | }
487 | goto start;
488 | }
489 | break;
490 | case WHILE:
491 | {
492 | char *type = get_type_recursive(type_checker, current->children[0]);
493 | if (!type || (strcmp(type, "i32") &&
494 | (!starts_with(type, "i") && !starts_with(type, "u") &&
495 | type[strlen(type)] == '?')))
496 | {
497 | char *buffer = malloc(1024);
498 | sprintf(buffer,
499 | "While loops can only be used using enumerable "
500 | "conditions. You gave a type '%s' but a while loop "
501 | "requires an integer type.",
502 | type);
503 | put_error(buffer, 0, current->children[0]->node_token);
504 | }
505 | }
506 | break;
507 | case EXTERN:
508 | {
509 | for (size_t i = 0; i < type_checker->n_func; ++i)
510 | {
511 | if (!strcmp(type_checker->functions[i].title,
512 | current->children[0]->node_token.text))
513 | {
514 | char *msg = (char *)malloc(1024);
515 | memset(msg, 0, 1024);
516 | strcat(msg, "Function '");
517 | strcat(msg, type_checker->functions[i].title);
518 | strcat(msg, "' has been redefined.");
519 | put_error(msg, 0, current->children[1]->node_token);
520 | }
521 | }
522 | // Extern is sort of a black box for the compiler, we have no idea
523 | // what is actually going on, since this links to any non-lowfish
524 | // function.
525 | printf("WARNING: UNSAFE FUNCTION DEFINITION FOR '%s': %s",
526 | current->children[0]->node_token.text,
527 | " The type checker is unable to check functions used from "
528 | "extern make sure that you match the argument count and "
529 | "type.\n");
530 | type_checker->functions =
531 | realloc(type_checker->functions,
532 | (++type_checker->n_func) * sizeof(function));
533 | char *buff = calloc(1, strlen(current->children[0]->node_token.text) + 1);
534 | int i = 0;
535 | int n = 0;
536 | for (i = 1; i < strlen(current->children[0]->node_token.text) - 1; ++i)
537 | {
538 | printf("%c\n", current->children[0]->node_token.text[i]);
539 | buff[n] = current->children[0]->node_token.text[i];
540 | ++n;
541 | }
542 | printf("thing:%d\n", buff);
543 | type_checker->functions[type_checker->n_func - 1] =
544 | (function){buff, "unk", -1};
545 | }
546 | break;
547 | case FUNCTION:
548 | {
549 | for (size_t i = 0; i < type_checker->n_func; ++i)
550 | {
551 | if (!strcmp(type_checker->functions[i].title,
552 | current->children[1]->node_token.text))
553 | {
554 | char *msg = (char *)malloc(1024);
555 | memset(msg, 0, 1024);
556 | strcat(msg, "Function '");
557 | strcat(msg, type_checker->functions[i].title);
558 | strcat(msg, "' has been redefined.");
559 | put_error(msg, 0, current->children[1]->node_token);
560 | }
561 | }
562 | type_checker->functions =
563 | realloc(type_checker->functions,
564 | (++type_checker->n_func) * sizeof(function));
565 | type_checker->functions[type_checker->n_func - 1] = (function){
566 | current->children[1]->node_token.text,
567 | current->children[0]->node_token.text, current->n_child - 3};
568 | }
569 | break;
570 | case FUNCTION_CALL:
571 | {
572 | bool found = false;
573 | size_t index = 0;
574 | for (size_t i = 0; i < type_checker->n_func; ++i)
575 | {
576 | if (!strcmp(type_checker->functions[i].title,
577 | current->node_token.text))
578 | {
579 | found = true;
580 | index = i;
581 | }
582 | }
583 | if (!found)
584 | {
585 | char *buffer = malloc(1024);
586 | memset(buffer, 0, 1024);
587 | sprintf(buffer, "Function '%s' doesn't exist.",
588 | current->node_token.text);
589 | put_error(buffer, 0, current->node_token);
590 | free(buffer);
591 | }
592 |
593 | if (type_checker->functions[index].n_args == -1)
594 | {
595 | /*
596 | This is done because -1 means the function is externed and I
597 | cant type check it.
598 | */
599 | goto end;
600 | }
601 | if (current->n_child > type_checker->functions[index].n_args)
602 | {
603 | char *buffer = malloc(1024);
604 | memset(buffer, 0, 1024);
605 | sprintf(buffer, "To many args for Function '%s'.",
606 | current->node_token.text);
607 | put_error(buffer, 0, current->node_token);
608 | free(buffer);
609 | }
610 | if (current->n_child < type_checker->functions[index].n_args)
611 | {
612 | char *buffer = malloc(1024);
613 | memset(buffer, 0, 1024);
614 | sprintf(buffer, "To few args for Function '%s'.",
615 | current->node_token.text);
616 | put_error(buffer, 0, current->node_token);
617 | free(buffer);
618 | }
619 | }
620 | break;
621 | case VARDECL:
622 | {
623 | node *type = get_child_recursive(current, TYPE);
624 | node *title = get_child_recursive(current, TOKENNODE);
625 | node *func = get_parent(current, FUNCTION)->children[1];
626 | if (!func)
627 | {
628 | printf("HOW IS THIS POSSIBLE???\n");
629 | exit(9001); // hehe over 9000
630 | }
631 | variable v =
632 | (variable){title->node_token.text, type->node_token.text,
633 | type_checker->scope,
634 | get_function(type_checker, func->node_token.text)};
635 | if (!type_checker->variables)
636 | {
637 | type_checker->variables = malloc(sizeof(variable));
638 | *type_checker->variables = v;
639 | type_checker->n_var = 1;
640 | }
641 | else
642 | {
643 | type_checker->variables =
644 | realloc(type_checker->variables,
645 | sizeof(variable) * (type_checker->n_var + 1));
646 | type_checker->variables[type_checker->n_var] = v;
647 | type_checker->n_var++;
648 | }
649 | }
650 | break;
651 | case ASSIGNMENT:
652 | {
653 | if (current->node_token.type == DEREF)
654 | {
655 | node *title = get_child_recursive(current, TOKENNODE);
656 | node *node_func = get_parent(current, FUNCTION)->children[1];
657 | function *func =
658 | get_function(type_checker, node_func->node_token.text);
659 | variable *var = get_var(type_checker, title->node_token.text,
660 | type_checker->scope, func);
661 | if (!var)
662 | {
663 | // no need to free because put_error exits the program.
664 | char *buffer = malloc(1024);
665 | sprintf(buffer,
666 | "The variable you are trying to use '%s' does not "
667 | "exist.",
668 | title->node_token.text);
669 | put_error(buffer, 0, title->node_token);
670 | }
671 | if (!var->pointing_to)
672 | {
673 | char *buffer = malloc(1024);
674 | sprintf(buffer,
675 | "Variable '%s' is not a pointer and cannot be "
676 | "dereferenced.",
677 | var->title);
678 | put_error(buffer, 0, title->node_token);
679 | }
680 | }
681 | if (has_child_recursive(current, FUNCTION_CALL))
682 | {
683 | node *call = get_child_recursive(current, FUNCTION_CALL);
684 | node *title = get_child_recursive(current, TOKENNODE);
685 | node *node_func = get_parent(current, FUNCTION)->children[1];
686 | function *func =
687 | get_function(type_checker, node_func->node_token.text);
688 | variable *var = get_var(type_checker, title->node_token.text,
689 | type_checker->scope, func);
690 | if (!var)
691 | {
692 | // no need to free because put_error exits the program.
693 | char *buffer = malloc(1024);
694 | sprintf(buffer,
695 | "The variable you are trying to use '%s' does not "
696 | "exist.",
697 | title->node_token.text);
698 | put_error(buffer, 0, title->node_token);
699 | }
700 | if (func)
701 | {
702 | if (var)
703 | {
704 | if (strcmp(var->type, func->type))
705 | {
706 | put_error_incompatible_types_assignment(
707 | var->type, func->type,
708 | call); // gotta be careful since some tokens
709 | // dont have a line number and column
710 | // stupid me I should've thougth a small
711 | // bit..
712 | }
713 | }
714 | }
715 | // if the function doesnt exist then later on when the type
716 | // checker actually gets to the function call an error will be
717 | // shown.
718 | }
719 | else if (has_child_recursive(
720 | current,
721 | BASICEXPRESSION)) // remember that damn else if
722 | {
723 | node *basic_expr =
724 | get_child_recursive(current, BASICEXPRESSION)->children[0];
725 | if (basic_expr->node_token.type == ID)
726 | {
727 | node *title = get_child_recursive(current, TOKENNODE);
728 | node *node_func =
729 | get_parent(current, FUNCTION)->children[1];
730 | function *func =
731 | get_function(type_checker, node_func->node_token.text);
732 | variable *var =
733 | get_var(type_checker, title->node_token.text,
734 | type_checker->scope, func);
735 | variable *var_get =
736 | get_var(type_checker, basic_expr->node_token.text,
737 | type_checker->scope, func);
738 | if (!var)
739 | {
740 | // no need to free because put_error exits the program.
741 | char *buffer = malloc(1024);
742 | sprintf(buffer,
743 | "The variable you are trying to use '%s' does "
744 | "not exist.",
745 | title->node_token.text);
746 | put_error(buffer, 0, title->node_token);
747 | }
748 | if (!var_get)
749 | {
750 | // no need to free because put_error exits the program.
751 | char *buffer = malloc(1024);
752 | sprintf(buffer,
753 | "The variable you are trying to use '%s' does "
754 | "not exist.",
755 | basic_expr->node_token.text);
756 | put_error(buffer, 0, basic_expr->node_token);
757 | }
758 | if (strcmp(var->type, var_get->type))
759 | {
760 | put_error_incompatible_types_assignment(
761 | var->type, var_get->type, basic_expr);
762 | }
763 | }
764 | else if (basic_expr->node_token.type == DEREF)
765 | {
766 | node *title = get_child_recursive(current, TOKENNODE);
767 | node *node_func =
768 | get_parent(current, FUNCTION)->children[1];
769 | function *func =
770 | get_function(type_checker, node_func->node_token.text);
771 | variable *var =
772 | get_var(type_checker, title->node_token.text,
773 | type_checker->scope, func);
774 | variable *var_get =
775 | get_var(type_checker, basic_expr->node_token.text,
776 | type_checker->scope, func);
777 | if (!var)
778 | {
779 | // no need to free because put_error exits the program.
780 | char *buffer = malloc(1024);
781 | sprintf(buffer,
782 | "The variable you are trying to use '%s' does "
783 | "not exist.",
784 | title->node_token.text);
785 | put_error(buffer, 0, title->node_token);
786 | }
787 | if (!var_get)
788 | {
789 | // no need to free because put_error exits the program.
790 | char *buffer = malloc(1024);
791 | sprintf(buffer,
792 | "The variable you are trying to use '%s' does "
793 | "not exist.",
794 | basic_expr->node_token.text);
795 | put_error(buffer, 0, basic_expr->node_token);
796 | }
797 | if (title->node_token.type == DEREF)
798 | {
799 | var = var->pointing_to;
800 | }
801 | if (!var_get->pointing_to)
802 | {
803 | char *buffer = malloc(1024);
804 | sprintf(buffer,
805 | "Variable '%s' is not a pointer and cannot be "
806 | "dereferenced.",
807 | var_get->title);
808 | put_error(buffer, 0, basic_expr->node_token);
809 | }
810 | if (strcmp(var->type, var_get->pointing_to->type))
811 | {
812 | printf("'%s', '%s'\n", var->type, var_get->type);
813 | put_error_incompatible_types_assignment(
814 | var->type, var_get->pointing_to->type, basic_expr);
815 | }
816 | }
817 | else if (basic_expr->node_token.type == REF)
818 | {
819 | node *title = get_child_recursive(current, TOKENNODE);
820 | node *node_func =
821 | get_parent(current, FUNCTION)->children[1];
822 | function *func =
823 | get_function(type_checker, node_func->node_token.text);
824 | variable *var =
825 | get_var(type_checker, title->node_token.text,
826 | type_checker->scope, func);
827 | variable *var_get =
828 | get_var(type_checker, basic_expr->node_token.text,
829 | type_checker->scope, func);
830 | if (!var)
831 | {
832 | // no need to free because put_error exits the program.
833 | char *buffer = malloc(1024);
834 | sprintf(buffer,
835 | "The variable you are trying to use '%s' does "
836 | "not exist.",
837 | title->node_token.text);
838 | put_error(buffer, 0, title->node_token);
839 | }
840 | if (!var_get)
841 | {
842 | char *buffer = malloc(1024);
843 | sprintf(buffer,
844 | "The variable you are trying to use '%s' does "
845 | "not exist.",
846 | basic_expr->node_token.text);
847 | put_error(buffer, 0, basic_expr->node_token);
848 | }
849 | if (title->node_token.type == DEREF)
850 | {
851 | var = var->pointing_to;
852 | }
853 | if (var_get->type && (!strcmp("u8", var_get->type) ||
854 | !strcmp("i8", var_get->type)))
855 | {
856 | if (strcmp(var->type, "ptr8"))
857 | {
858 | put_error_incompatible_types_assignment(
859 | var->type, "ptr8", basic_expr);
860 | }
861 | var->pointing_to = var_get;
862 | }
863 |
864 | if (var_get->type && (!strcmp("u16", var_get->type) ||
865 | !strcmp("i16", var_get->type)))
866 | {
867 | if (strcmp(var->type, "ptr16"))
868 | {
869 | put_error_incompatible_types_assignment(
870 | var->type, "ptr16", basic_expr);
871 | }
872 | var->pointing_to = var_get;
873 | }
874 |
875 | if (var_get->type && (!strcmp("u32", var_get->type) ||
876 | !strcmp("i32", var_get->type)))
877 | {
878 | if (strcmp(var->type, "ptr32"))
879 | {
880 | put_error_incompatible_types_assignment(
881 | var->type, "ptr32", basic_expr);
882 | }
883 | var->pointing_to = var_get;
884 | }
885 |
886 | if (starts_with(var_get->type, "ptr"))
887 | {
888 | if (strcmp(var->type, "ptr"))
889 | {
890 | put_error_incompatible_types_assignment(
891 | var->type, "ptr", basic_expr);
892 | }
893 | var->pointing_to = var_get;
894 | }
895 | }
896 | else if (basic_expr->node_token.type == STRING)
897 | {
898 | node *title = get_child_recursive(current, TOKENNODE);
899 | node *node_func =
900 | get_parent(current, FUNCTION)->children[1];
901 | function *func =
902 | get_function(type_checker, node_func->node_token.text);
903 | variable *var =
904 | get_var(type_checker, title->node_token.text,
905 | type_checker->scope, func);
906 | if (!var)
907 | {
908 | // no need to free because put_error exits the program.
909 | char *buffer = malloc(1024);
910 | sprintf(buffer,
911 | "The variable you are trying to use '%s' does "
912 | "not exist.",
913 | title->node_token.text);
914 | put_error(buffer, 0, title->node_token);
915 | }
916 | if (title->node_token.type == DEREF)
917 | {
918 | var = var->pointing_to;
919 | }
920 | if (strlen(basic_expr->node_token.text) == 1)
921 | {
922 | // "a" is a char or a string
923 | // "aa" is a string, the distinction is multiple
924 | // characters. strings dont exist tho so we use 'ptr8'
925 | // which is alot more descriptive.
926 | if (strcmp(var->type, "u8") &&
927 | strcmp(var->type, "i8") &&
928 | strcmp(var->type, "ptr8"))
929 | {
930 | put_error_incompatible_types_assignment(
931 | var->type, "u8", basic_expr);
932 | }
933 | }
934 | else if (strcmp(var->type, "ptr8"))
935 | {
936 | put_error_incompatible_types_assignment(
937 | var->type, "ptr8", basic_expr);
938 | }
939 | }
940 | else if (basic_expr->node_token.type == NUMBER)
941 | {
942 | node *title = get_child_recursive(current, TOKENNODE);
943 | node *node_func =
944 | get_parent(current, FUNCTION)->children[1];
945 | function *func =
946 | get_function(type_checker, node_func->node_token.text);
947 | variable *var =
948 | get_var(type_checker, title->node_token.text,
949 | type_checker->scope, func);
950 | if (title->node_token.type == DEREF)
951 | {
952 | var = var->pointing_to;
953 | }
954 | if (strcmp(var->type, "i32") && strcmp(var->type, "i16") &&
955 | strcmp(var->type, "i8") && strcmp(var->type, "u8") &&
956 | strcmp(var->type, "u16") && strcmp(var->type, "u32"))
957 | {
958 | put_error_incompatible_types_assignment(
959 | var->type, "i32", basic_expr);
960 | }
961 | }
962 | }
963 | }
964 | break;
965 | }
966 | end:
967 | for (size_t i = 0; i != current->n_child; ++i)
968 | {
969 | type_check_tree(current->children[i], type_checker);
970 | }
971 | return true;
972 | }
973 |
--------------------------------------------------------------------------------
/src/typechecker/typechecker.h:
--------------------------------------------------------------------------------
1 | #ifndef TYPE_CHECKER_H
2 |
3 | #define TYPE_CHECKER_H
4 | #include "../parser/parser.h"
5 |
6 | typedef struct
7 | {
8 | char *title;
9 | char *type;
10 | size_t n_args; // -1 means unknown, like for a C function.
11 | } function;
12 |
13 | typedef struct var
14 | {
15 | char *title;
16 | char *type;
17 | size_t scope;
18 | function *func;
19 | struct var *pointing_to;
20 | } variable;
21 |
22 | typedef struct
23 | {
24 | size_t n_func;
25 | function *functions;
26 | size_t n_var;
27 | variable *variables;
28 | size_t n_label;
29 | char **labels;
30 | size_t scope;
31 | } typechecker;
32 |
33 | bool type_check_tree(node *tree, typechecker *type_checker);
34 | void restructure_parents(node *tree);
35 | function *get_function(typechecker *type_checker, char *title);
36 |
37 | variable *get_var(typechecker *type_checker, char *title, size_t scope,
38 | function *func);
39 | char *get_type_recursive(typechecker *type_checker, node *expr);
40 | node *eval(node *x, node *parent);
41 | #endif
42 |
--------------------------------------------------------------------------------
/src/util.c:
--------------------------------------------------------------------------------
1 | #include "util.h"
2 | #include
3 | #include
4 |
5 | char *read_file(char *path)
6 | {
7 | FILE *ptr;
8 | char ch;
9 | ptr = fopen(path, "r");
10 | if (ptr == NULL)
11 | {
12 | printf("Couldn't read file '%s'\n", path);
13 | }
14 | size_t len = 0;
15 | do
16 | {
17 | ch = fgetc(ptr);
18 | ++len;
19 | } while (ch != EOF);
20 | char *output = malloc(len);
21 | size_t i = 0;
22 | fclose(ptr);
23 | ptr = fopen(path, "r");
24 | while (i < len)
25 | {
26 | output[i] = fgetc(ptr);
27 | ++i;
28 | }
29 | output[len - 1] = 0;
30 | return output;
31 | }
32 |
33 | inline void **append(void **buffer, void *data, size_t len)
34 | {
35 | buffer = realloc(buffer, len + 1);
36 | buffer[len] = data;
37 | return buffer;
38 | }
39 | void print_n_times(char *string, int n)
40 | {
41 | for (int i = 0; i != n; ++i)
42 | {
43 | printf("%s", string);
44 | }
45 | }
--------------------------------------------------------------------------------
/src/util.h:
--------------------------------------------------------------------------------
1 | #ifndef UTIL_H
2 |
3 | #define UTIL_H
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #define true 1
11 | #define false 0
12 |
13 | char *read_file(char *path);
14 |
15 | void **append(void **buffer, void *data, size_t len);
16 |
17 | void print_n_times(char *string, int n);
18 |
19 | #endif
20 |
--------------------------------------------------------------------------------
/test.lf:
--------------------------------------------------------------------------------
1 | extern("printf");
2 | i32 main()
3 | {
4 | printf("Hello, World");
5 | }
--------------------------------------------------------------------------------
/tests/few_call.lf:
--------------------------------------------------------------------------------
1 | i32 x(i32 a)
2 | {
3 | return a;
4 | }
5 |
6 | i32 main()
7 | {
8 | x();
9 | }
10 |
--------------------------------------------------------------------------------
/tests/fun.lf:
--------------------------------------------------------------------------------
1 | i32 main(i32 argc, ptr argv)
2 | {
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/tests/fun.lf.expected:
--------------------------------------------------------------------------------
1 |
2 | {
3 |
4 | {
5 |
6 |
7 |
8 | {
9 |
10 |
11 | }
12 |
13 | {
14 |
15 |
16 | }
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/funcall.lf:
--------------------------------------------------------------------------------
1 | i32 a()
2 | {
3 | i32 x = 0;
4 | return x;
5 | }
6 | i32 b()
7 | {
8 | a();
9 | }
10 |
--------------------------------------------------------------------------------
/tests/funcall.lf.expected:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/tests/test.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | def test(a):
4 | os.system(f"./lowfish tests/{a} > out.txt")
5 | f = open('out.txt', 'r')
6 | got = f.read()
7 | f2 = open(f'tests/{a}.expected', 'r')
8 | expected = f.read()
9 | f.close()
10 | f2.close()
11 | return [expected in got, a, got]
12 |
13 | def print_results(x):
14 | print(f'-- Tested file: {x[1]} --')
15 | print(f'-- Succeeded: {x[0]} --')
16 | if x[0] == False:
17 | print(f'-- What We got: \'\n{x[2]}\n\' --')
18 |
19 | dirs = list(filter((lambda a : a.endswith('.lf')), os.listdir('./tests/')))
20 | results = list(map(test ,dirs))
21 | list(map(print_results, results))
22 |
23 |
--------------------------------------------------------------------------------
/tests/variable.lf:
--------------------------------------------------------------------------------
1 | i32 main()
2 | {
3 | i32 x = 55;
4 | i8 y = 5;
5 | i32 z = x;
6 | }
7 |
--------------------------------------------------------------------------------
/tests/variable.lf.expected:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/tests/variable_func_call.lf:
--------------------------------------------------------------------------------
1 | i32 x(i32 a)
2 | {
3 | return a;
4 | }
5 | i32 main()
6 | {
7 | i32 b = 5;
8 | i32 n = x(a);
9 | }
10 |
--------------------------------------------------------------------------------
/tests/variable_func_call.lf.expected:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------