Compare commits
No commits in common. "master" and "yacc" have entirely different histories.
31 changed files with 192 additions and 2500 deletions
338
LICENSE.txt
338
LICENSE.txt
|
@ -1,338 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
<https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Moe Ghoul>, 1 April 1989
|
||||
Moe Ghoul, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
8
Makefile
8
Makefile
|
@ -3,7 +3,7 @@
|
|||
|
||||
OUTNAME = flisp
|
||||
|
||||
CFLAGS = -std=c99 -O0 -flto -Wall -Wextra -g -pipe -Wno-cast-function-type
|
||||
CFLAGS = -O0 -Wall -Wextra -g -pipe
|
||||
|
||||
CC = gcc
|
||||
|
||||
|
@ -20,6 +20,7 @@ BUILD_DIR = build
|
|||
SRC_DIR = src
|
||||
|
||||
OBJS = $(patsubst $(SRC_DIR)/%.c,build-tmp/%.o,$(wildcard $(SRC_DIR)/*.c))
|
||||
OBJS += build-tmp/y.tab.o build-tmp/lex.yy.o
|
||||
|
||||
all: | builddir yacc build builddir2
|
||||
|
||||
|
@ -36,12 +37,9 @@ builddir:
|
|||
@- mv $(wildcard $(BUILD_DIR)/*.o) build-tmp/
|
||||
|
||||
yacc: src/parser.y src/parser.l
|
||||
cd src && bison -y -d parser.y && lex parser.l
|
||||
cd src && yacc -d -g parser.y && lex parser.l
|
||||
$(CC) -c src/y.tab.c -o build-tmp/y.tab.o $(CFLAGS)
|
||||
$(CC) -c src/lex.yy.c -o build-tmp/lex.yy.o $(CFLAGS)
|
||||
ifneq ($(filter $(OBJS), build-tmp/y.tab.o),build-tmp/y.tab.o)
|
||||
$(eval OBJS += build-tmp/y.tab.o build-tmp/lex.yy.o)
|
||||
endif
|
||||
|
||||
build-tmp/%.o : $(SRC_DIR)/%.c
|
||||
${CC} -c $< -o $@ ${CFLAGS}
|
||||
|
|
23
README.md
23
README.md
|
@ -1,23 +0,0 @@
|
|||
# fLisp
|
||||
|
||||
All of the code under src/ is under the GPLv2 exclusively
|
||||
The code in examples/ is public domain
|
||||
|
||||
## See spec.md for the actual language and bytecode docs
|
||||
|
||||
## Building
|
||||
|
||||
Pre-requisites:
|
||||
- Bison
|
||||
- lex
|
||||
- A C99 compiler
|
||||
- GNU Make
|
||||
|
||||
### Unix
|
||||
Running `make` (or `gmake` for BSDs), should work on most Unix systems.
|
||||
It produces an executable called `flisp.amd64`
|
||||
|
||||
### Windows
|
||||
To meet the previously mentionned pre-requisites, you need to use mingw.
|
||||
I recommend installing w64devkit, then compiling Bison and Flex from source.
|
||||
Run `make win`, twice
|
7
TODO.md
7
TODO.md
|
@ -1,7 +0,0 @@
|
|||
- Benchmarks
|
||||
- Tests
|
||||
- Type checks
|
||||
- Scopes
|
||||
|
||||
- Type propagation
|
||||
- Bytecode gen
|
|
@ -1,14 +0,0 @@
|
|||
int main(){
|
||||
for(int i = 0; i < 10000; i++){
|
||||
int a = 0;
|
||||
int b = 1;
|
||||
int c;
|
||||
int n = 0;
|
||||
while(n < 40){
|
||||
c = b;
|
||||
b += a;
|
||||
a = c;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
(var:int i 0)
|
||||
(while (< i 10000)
|
||||
(var:int a 0)
|
||||
(var:int b 1)
|
||||
(var:int c)
|
||||
(var:int n 0)
|
||||
|
||||
(while (< n 40)
|
||||
(set c b)
|
||||
(set b (+ a b))
|
||||
(set a c)
|
||||
(set n (+ n 1))
|
||||
)
|
||||
(set i (+ i 1))
|
||||
)
|
|
@ -1,13 +0,0 @@
|
|||
i = 0
|
||||
while i < 10000:
|
||||
a = 0
|
||||
b = 1
|
||||
c = 0
|
||||
n = 0
|
||||
|
||||
while n < 40:
|
||||
c = b
|
||||
b += a
|
||||
a = c
|
||||
n += 1
|
||||
i+=1
|
|
@ -1,5 +0,0 @@
|
|||
(var:fix a (:fix 0.1))
|
||||
(var:fix b (:fix 0.2))
|
||||
|
||||
(write (+ a b))
|
||||
(newline)
|
|
@ -1,2 +1,2 @@
|
|||
(import console)
|
||||
(write "Hello world")
|
||||
(newline)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
(if (= guess number)
|
||||
(write "You won !")
|
||||
(newline)
|
||||
(set won 1)
|
||||
(won 1)
|
||||
)
|
||||
)
|
||||
(if (! won)
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
(fn (a)
|
||||
(fn (b)
|
||||
(write 1)
|
||||
)
|
||||
(write 2)
|
||||
)
|
|
@ -1,6 +0,0 @@
|
|||
(var:str a "1234")
|
||||
(var:int b (:int a))
|
||||
(write a)
|
||||
(newline)
|
||||
(write b)
|
||||
(newline)
|
|
@ -1,27 +1,8 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#define FL_EPSILON (1e-7f)
|
||||
#define FL_EPSILON (1e-6f)
|
||||
|
||||
enum OpTypes {
|
||||
OP_add = 0,
|
||||
|
@ -76,12 +57,18 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
|
||||
uint is_array : 1;
|
||||
uint is_strong : 1;
|
||||
uint type : 14;
|
||||
uint is_array : 1;
|
||||
uint type : 15;
|
||||
|
||||
} PACKED Tag;
|
||||
|
||||
typedef struct {
|
||||
|
||||
Tag params[8];
|
||||
i32 n_param;
|
||||
|
||||
} FnSig;
|
||||
|
||||
typedef struct {
|
||||
|
||||
u8 type; // OpTypes
|
||||
|
@ -91,10 +78,7 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
|
||||
union {
|
||||
i32 value;
|
||||
float vfl;
|
||||
};
|
||||
u32 value;
|
||||
u8 __padding[2];
|
||||
|
||||
} PACKED Value4B;
|
||||
|
@ -106,62 +90,32 @@ typedef struct {
|
|||
|
||||
} PACKED ValueArray;
|
||||
|
||||
typedef struct {
|
||||
|
||||
// Cast to a 48bit FnSig ptr
|
||||
u8 __raw_bytes[6];
|
||||
|
||||
} PACKED ValueFn;
|
||||
|
||||
typedef struct {
|
||||
|
||||
PACKED union {
|
||||
char str[4];
|
||||
u32 pos;
|
||||
char str[5];
|
||||
PACKED struct {
|
||||
u32 pos;
|
||||
u8 __padding;
|
||||
};
|
||||
};
|
||||
u16 len;
|
||||
u8 len;
|
||||
|
||||
} PACKED ValueStr;
|
||||
|
||||
typedef struct {
|
||||
|
||||
|
||||
|
||||
PACKED union {
|
||||
Value4B v4B;
|
||||
ValueArray varray;
|
||||
ValueStr vstr;
|
||||
ValueFn vfn;
|
||||
};
|
||||
|
||||
Tag tag;
|
||||
|
||||
} PACKED Value;
|
||||
|
||||
typedef Value (bi_fn_t)(void);
|
||||
|
||||
typedef struct {
|
||||
|
||||
Tag params[8];
|
||||
Tag output;
|
||||
i16 n_param;
|
||||
i16 is_builtin;
|
||||
union {
|
||||
Opcode *jmpto;
|
||||
void *stmt;
|
||||
bi_fn_t *bi;
|
||||
};
|
||||
|
||||
} FnSig;
|
||||
|
||||
#ifndef win
|
||||
_Static_assert(sizeof(Value) == 8, "Value isn't the right size");
|
||||
_Static_assert(sizeof(Value) == 8);
|
||||
#endif
|
||||
_Static_assert(sizeof(Tag) <= 2, "Tag is too large for tomfoolery");
|
||||
|
||||
static inline FnSig *get_fnsig(Value *x){
|
||||
u64 rval = *((u64*)x);
|
||||
rval &= 0xFFFFFFFFFFFF; // 48bits - should be (mostly) fine
|
||||
return (void*)rval;
|
||||
}
|
||||
|
||||
extern Tag ntag;
|
||||
extern Tag atag;
|
||||
_Static_assert(sizeof(Tag) <= sizeof(i32));
|
||||
|
|
|
@ -1,22 +1,3 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
|
124
src/code_defs.h
124
src/code_defs.h
|
@ -1,82 +1,60 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "byte_defs.h"
|
||||
#include "types.h"
|
||||
#include "hash.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#define SYMBOL_MAP_S (1024*4)
|
||||
#define SYMBOL_MAP_S (1024*16)
|
||||
|
||||
enum StatementTypes {
|
||||
ST_None = 0, // Not processed yet
|
||||
ST_Call = 1, // Builtin function call
|
||||
ST_Const = 2, // Constant
|
||||
ST_Var = 3, // Free variable
|
||||
ST_Block = 4, // Scope blocks
|
||||
ST_Varuse = 5, // Variable func call
|
||||
ST_Set = 6, // Set variable
|
||||
ST_Call = 1, // Any kind of function call
|
||||
ST_Builtin = 2, // All special builtins (declarations, control flow...)
|
||||
ST_Const = 3, // Constant
|
||||
ST_Var = 4, // Variable
|
||||
ST_Block = 5, // Scope blocks
|
||||
ST__end
|
||||
};
|
||||
|
||||
// Special expressions and ones that map directly to bytecode
|
||||
// Should mesh with StatementTypes
|
||||
enum BuiltinStatements {
|
||||
BI_var = ST__end,
|
||||
BI_let,
|
||||
BI_if,
|
||||
BI_else,
|
||||
BI_while,
|
||||
BI_fn,
|
||||
BI_import,
|
||||
BI_is,
|
||||
BI_cast,
|
||||
BI_add,
|
||||
BI_sub,
|
||||
BI_mul,
|
||||
BI_div,
|
||||
BI_mod,
|
||||
BI_sml,
|
||||
BI_sml_eq,
|
||||
BI_eq,
|
||||
BI_gt_eq,
|
||||
BI_gt,
|
||||
BI_not,
|
||||
BI_and,
|
||||
BI_or,
|
||||
BI_len,
|
||||
BI_push,
|
||||
BI_pop,
|
||||
BI_write,
|
||||
BI_nwline,
|
||||
BI_assign = 6,
|
||||
BI_var = 7,
|
||||
BI_let = 8,
|
||||
BI_if = 9,
|
||||
BI_else = 10,
|
||||
BI_while = 11,
|
||||
BI_fn = 12,
|
||||
BI_import = 13,
|
||||
BI_add = 14,
|
||||
BI_sub = 15,
|
||||
BI_mul = 16,
|
||||
BI_div = 17,
|
||||
BI_mod = 18,
|
||||
BI_sml = 19,
|
||||
BI_sml_eq = 20,
|
||||
BI_eq = 21,
|
||||
BI_gt_eq = 22,
|
||||
BI_gt = 23,
|
||||
BI_not = 24,
|
||||
BI_and = 25,
|
||||
BI_or = 26,
|
||||
BI_is = 27,
|
||||
BI_cast = 28,
|
||||
BI_len = 29,
|
||||
BI_push = 30,
|
||||
BI_pop = 31,
|
||||
BI__end
|
||||
};
|
||||
|
||||
|
||||
struct PACKED Statement {
|
||||
struct Statement {
|
||||
|
||||
u8 type;
|
||||
u8 is_const; // Statement is constant, != is a constant - TODO : implem
|
||||
i16 scope;
|
||||
i32 child_n;
|
||||
i32 type;
|
||||
i32 is_const; // Statement is constant, != is a constant - TODO : implem
|
||||
void **children;
|
||||
void *parent;
|
||||
i32 child_n;
|
||||
union {
|
||||
Value cons;
|
||||
struct {
|
||||
|
@ -84,43 +62,27 @@ struct PACKED Statement {
|
|||
Tag var_type;
|
||||
};
|
||||
FnSig *func;
|
||||
void *els; // "Bodge" - pointer to else for if's
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
typedef struct Statement Statement;
|
||||
|
||||
// Function signature for the tree walk interpreter
|
||||
typedef struct {
|
||||
|
||||
i32 param_id[8]; // Ids to fill for parameters
|
||||
Statement *stat; // Statement to jump to
|
||||
|
||||
} InterprSig;
|
||||
|
||||
// In practice, this is allocated in parse.c
|
||||
typedef struct {
|
||||
|
||||
// Debug messages
|
||||
// TODO
|
||||
// Kept for debug messages
|
||||
i32 curr_line;
|
||||
i32 curr_column;
|
||||
|
||||
i32 scope_id;
|
||||
i32 curr_scope;
|
||||
i32 scope_stack[256];
|
||||
i32 max_statement; // Unused while parsing
|
||||
i32 curr_statement;
|
||||
|
||||
HashMap symbol_map;
|
||||
|
||||
i32 fn_n;
|
||||
FnSig *funcs;
|
||||
#ifdef INTERPR
|
||||
InterprSig *interpr_sigs;
|
||||
#endif
|
||||
|
||||
i32 stack_size;
|
||||
i32 curr_statement;
|
||||
Statement statements[];
|
||||
|
||||
} ASTStack;
|
||||
|
||||
_Static_assert(BI_assign == ST__end);
|
||||
|
|
30
src/config.h
30
src/config.h
|
@ -1,34 +1,6 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Debug checks
|
||||
// 0 : None (still features runtime debug)
|
||||
// 1 : Some checks
|
||||
// 1 : Some checks and prints
|
||||
// 2 : All checks
|
||||
#define DEBUG 2
|
||||
|
||||
// Debug logs
|
||||
// 0 : None
|
||||
// 1 : All misc debug logs
|
||||
#define LOG 1
|
||||
|
||||
// TODO : Automate this
|
||||
#define INTERPR
|
||||
|
|
|
@ -1,797 +0,0 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "fixed.h"
|
||||
#include "types.h"
|
||||
#include "config.h"
|
||||
#include "code_defs.h"
|
||||
#include "byte_defs.h"
|
||||
#include "exec_common.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
u32 pos;
|
||||
u32 size;
|
||||
|
||||
} AllocBlock;
|
||||
|
||||
#define EXT_BLOCK 4096
|
||||
|
||||
void *internal_buf;
|
||||
AllocBlock *blocks;
|
||||
u32 *usage; // bitmap for usage, by 8byte chunks
|
||||
size_t internal_size;
|
||||
u32 block_count;
|
||||
|
||||
// Utils
|
||||
|
||||
void runtime_err(char *s){
|
||||
fprintf(stderr,"Runtime Error : %s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int evaluate(Value val){
|
||||
if(val.tag.is_array)
|
||||
return 0;
|
||||
switch(val.tag.type){
|
||||
case T_null:
|
||||
return 0;
|
||||
case T_int:
|
||||
case T_fix:
|
||||
return val.v4B.value;
|
||||
case T_float:
|
||||
return FL_EPSILON < fabs(val.v4B.vfl);
|
||||
case T_str:
|
||||
case T_fn:
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int alloc_extend(u32 size){
|
||||
size = (size/EXT_BLOCK+1)*EXT_BLOCK;
|
||||
internal_buf = realloc(internal_buf, internal_size+size);
|
||||
usage = realloc(usage, sizeof(u32)*(internal_size+size)/32/8);
|
||||
if(!internal_buf || !usage)
|
||||
return 1;
|
||||
memset(usage+(internal_size/32/8), 0, sizeof(u32)*size/32/8);
|
||||
internal_size += size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int block_cmpfunc(const void *_a, const void *_b){
|
||||
const AllocBlock *a = _a;
|
||||
const AllocBlock *b = _b;
|
||||
return b->pos - a->pos;
|
||||
}
|
||||
|
||||
AllocBlock *get_block(u32 pos){
|
||||
AllocBlock tmp = {.pos = pos};
|
||||
AllocBlock *ret = bsearch(&tmp, blocks, block_count, sizeof(AllocBlock),
|
||||
block_cmpfunc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int alloc_init(){
|
||||
blocks = malloc(sizeof(AllocBlock));
|
||||
block_count = 0;
|
||||
internal_buf = NULL;
|
||||
internal_size = 0;
|
||||
usage = NULL;
|
||||
if(!blocks || alloc_extend(EXT_BLOCK))
|
||||
return 1;
|
||||
// First 32bytes are reserved for null + alignement
|
||||
usage[0] = 0xF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void alloc_clean(){
|
||||
free(internal_buf);
|
||||
free(blocks);
|
||||
free(usage);
|
||||
}
|
||||
|
||||
u32 flisp_alloc(u32 size){
|
||||
u32 pos = 32;
|
||||
u32 curr_free = 0;
|
||||
while(pos < internal_size){
|
||||
if(usage[pos/32/8]){
|
||||
for(u32 opos = pos; pos < opos+32;){
|
||||
if((usage[pos/32/8]>>((pos/8)%32)) & 1)
|
||||
curr_free = 0;
|
||||
else
|
||||
curr_free+=8;
|
||||
pos+=8;
|
||||
if(curr_free >= size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
curr_free += 32*8;
|
||||
pos+=32*8;
|
||||
}
|
||||
if(curr_free >= size){
|
||||
blocks = realloc(blocks, sizeof(AllocBlock)*(block_count+1));
|
||||
if(!blocks)
|
||||
return 0;
|
||||
AllocBlock *block = &blocks[block_count++];
|
||||
block->pos = pos-curr_free;
|
||||
block->size = size;
|
||||
for(u32 i = block->pos; i < block->pos+size; i+=8){
|
||||
usage[i/32/8] |= 1<<((i/8)%32);
|
||||
}
|
||||
// Unvirtualize the memory
|
||||
memset(get_addr(block->pos),0xB00B5069,size);
|
||||
return block->pos;
|
||||
}
|
||||
}
|
||||
if(alloc_extend(size))
|
||||
return 0;
|
||||
|
||||
// Try again after extending the buffer
|
||||
return flisp_alloc(size);
|
||||
}
|
||||
|
||||
// TODO : make it efficient
|
||||
u32 flisp_realloc(u32 pos, u32 size){
|
||||
if(!pos)
|
||||
return flisp_alloc(size);
|
||||
u32 new = flisp_alloc(size);
|
||||
if(!new)
|
||||
return 0;
|
||||
AllocBlock *block = get_block(pos);
|
||||
memcpy(get_addr(new),get_addr(pos),block->size);
|
||||
flisp_free(pos);
|
||||
return new;
|
||||
}
|
||||
|
||||
void flisp_free(u32 pos){
|
||||
AllocBlock *ret = get_block(pos);
|
||||
if(!ret)
|
||||
return;
|
||||
i32 bpos = (size_t)(ret-blocks)/sizeof(AllocBlock);
|
||||
memset(get_addr(ret->pos), 0, ret->size);
|
||||
memmove(ret, ret+1, sizeof(AllocBlock) * (block_count-bpos-1));
|
||||
block_count--;
|
||||
}
|
||||
|
||||
void *get_addr(u32 pos){
|
||||
return internal_buf + pos;
|
||||
}
|
||||
|
||||
Value fl_write(Value a);
|
||||
|
||||
void print_ast1(Statement *base, i32 indent){
|
||||
i32 close_parent = 1;
|
||||
printf("# ");
|
||||
for(int i = 0; i < indent; i++)
|
||||
printf(" ");
|
||||
switch(base->type){
|
||||
case ST_None:
|
||||
printf("(none\n");
|
||||
break;
|
||||
case ST_Call:
|
||||
printf("(call<%lx>\n", (u64)base->func);
|
||||
break;
|
||||
case ST_Const:
|
||||
fl_write(base->cons);
|
||||
printf("\n");
|
||||
close_parent = 0;
|
||||
break;
|
||||
case ST_Var:
|
||||
printf("<%d>\n", base->var_id);
|
||||
close_parent = 0;
|
||||
break;
|
||||
case ST_Block:
|
||||
printf("(block\n");
|
||||
break;
|
||||
case ST_Varuse:
|
||||
printf("(use<%d>\n", base->var_id);
|
||||
break;
|
||||
case ST_Set:
|
||||
printf("(set<%d>\n", base->var_id);
|
||||
break;
|
||||
case BI_var:
|
||||
printf("(var<%d>:<%d>\n", base->var_id, base->var_type.type);
|
||||
break;
|
||||
case BI_if:
|
||||
printf("(if\n");
|
||||
break;
|
||||
case BI_else:
|
||||
printf("(else\n");
|
||||
break;
|
||||
case BI_while:
|
||||
printf("(while\n");
|
||||
break;
|
||||
case BI_is:
|
||||
printf("(is<%d>\n", base->var_type.type);
|
||||
break;
|
||||
case BI_cast:
|
||||
printf("(cast<%d>\n", base->var_type.type);
|
||||
break;
|
||||
default:
|
||||
printf("(other<%d>\n", base->type);
|
||||
break;
|
||||
}
|
||||
for(int i = 0; i < base->child_n; i++)
|
||||
print_ast1(base->children[i], indent+1);
|
||||
|
||||
if(close_parent){
|
||||
printf("# ");
|
||||
for(int i = 0; i < indent; i++)
|
||||
printf(" ");
|
||||
printf(")\n");
|
||||
}
|
||||
}
|
||||
|
||||
void print_ast(Statement *base){
|
||||
#if LOG
|
||||
printf("# AST :\n");
|
||||
print_ast1(base, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
Value str_to_val(char *str, i32 len){
|
||||
if(len < 0)
|
||||
len = strlen(str);
|
||||
if(len > 65536){
|
||||
fprintf(stderr, "Warning : string is longer than 65k chars"
|
||||
" - will be trunucated\n");
|
||||
len = 65536;
|
||||
}
|
||||
Value retv;
|
||||
retv.tag = (Tag){.is_array = 0, .type = T_str};
|
||||
if(len > 4){
|
||||
u32 nstr = flisp_alloc(len);
|
||||
if(!nstr){
|
||||
retv.tag = ntag;
|
||||
return retv;
|
||||
}
|
||||
retv.vstr.pos = nstr;
|
||||
memcpy(get_addr(nstr),str,len);
|
||||
}
|
||||
else {
|
||||
for(i32 i = 0; i < len; i++)
|
||||
retv.vstr.str[i] = str[i];
|
||||
}
|
||||
retv.vstr.len = len;
|
||||
return retv;
|
||||
}
|
||||
|
||||
void clean_strval(Value str){
|
||||
if(str.vstr.len > 4)
|
||||
flisp_free(str.vstr.pos);
|
||||
}
|
||||
|
||||
// Lesser special functions
|
||||
|
||||
Value is(Tag tag, Value b){
|
||||
Value ret = {.tag = {0,0,T_int}};
|
||||
ret.v4B.value = tag.is_array == b.tag.is_array && tag.type == b.tag.type;
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef Value (cast_fn_t)(Value);
|
||||
|
||||
Value int_to_fix(Value x){
|
||||
x.tag.type = T_fix;
|
||||
x.v4B.value = fix(x.v4B.value);
|
||||
return x;
|
||||
}
|
||||
|
||||
Value int_to_flt(Value x){
|
||||
x.tag.type = T_float;
|
||||
x.v4B.vfl = (float)x.v4B.value;
|
||||
return x;
|
||||
}
|
||||
|
||||
Value fix_to_int(Value x){
|
||||
x.tag.type = T_int;
|
||||
x.v4B.value = ffloor(x.v4B.value);
|
||||
return x;
|
||||
}
|
||||
|
||||
Value fix_to_flt(Value x){
|
||||
x.tag.type = T_float;
|
||||
x.v4B.vfl = f2float(x.v4B.value);
|
||||
return x;
|
||||
}
|
||||
|
||||
Value flt_to_int(Value x){
|
||||
x.tag.type = T_int;
|
||||
x.v4B.value = (i32)(x.v4B.vfl);
|
||||
return x;
|
||||
}
|
||||
|
||||
Value flt_to_fix(Value x){
|
||||
x.tag.type = T_fix;
|
||||
x.v4B.value = fixfloat(x.v4B.vfl);
|
||||
return x;
|
||||
}
|
||||
|
||||
char tmpbuf[256];
|
||||
|
||||
Value int_to_str(Value x){
|
||||
i32 len = snprintf(tmpbuf, 256, "%d", x.v4B.value);
|
||||
len = len > 256 ? 256:len;
|
||||
Value retv = str_to_val(tmpbuf, len);
|
||||
return retv;
|
||||
}
|
||||
|
||||
Value fix_to_str(Value x){
|
||||
i32 len = snprintf(tmpbuf, 256, "%f", f2float(x.v4B.value));
|
||||
len = len > 256 ? 256:len;
|
||||
Value retv = str_to_val(tmpbuf, len);
|
||||
return retv;
|
||||
}
|
||||
|
||||
Value flt_to_str(Value x){
|
||||
i32 len = snprintf(tmpbuf, 256, "%f", x.v4B.vfl);
|
||||
len = len > 256 ? 256:len;
|
||||
Value retv = str_to_val(tmpbuf, len);
|
||||
return retv;
|
||||
}
|
||||
|
||||
Value vstr_to(Value x, i32 type){
|
||||
char *str;
|
||||
Value retv;
|
||||
if(x.vstr.len > 4)
|
||||
str = get_addr(x.vstr.pos);
|
||||
else
|
||||
str = x.vstr.str;
|
||||
char *nstr = malloc(x.vstr.len+1);
|
||||
if(!nstr){
|
||||
retv.tag = ntag;
|
||||
clean_strval(x);
|
||||
return retv;
|
||||
}
|
||||
memcpy(nstr, str, x.vstr.len);
|
||||
clean_strval(x);
|
||||
nstr[x.vstr.len] = '\0';
|
||||
i32 ret = 0;
|
||||
switch(type){
|
||||
case T_int:
|
||||
ret = sscanf(nstr, "%d", &retv.v4B.value);
|
||||
break;
|
||||
case T_fix:
|
||||
ret = sscanf(nstr, "%f", &retv.v4B.vfl);
|
||||
x.v4B.value = fix(x.v4B.vfl);
|
||||
break;
|
||||
case T_float:
|
||||
ret = sscanf(nstr, "%f", &retv.v4B.vfl);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(nstr);
|
||||
if(!ret){
|
||||
retv.tag = ntag;
|
||||
return retv;
|
||||
}
|
||||
retv.tag = (Tag){.is_array = 0, .type = type};
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
Value str_to_int(Value x){
|
||||
return vstr_to(x,T_int);
|
||||
}
|
||||
|
||||
Value str_to_fix(Value x){
|
||||
return vstr_to(x,T_fix);
|
||||
}
|
||||
|
||||
Value str_to_flt(Value x){
|
||||
return vstr_to(x,T_float);
|
||||
}
|
||||
|
||||
// [from][to]
|
||||
cast_fn_t *cast_table[4][4] = {
|
||||
{NULL , int_to_fix, int_to_flt, int_to_str},
|
||||
{fix_to_int, NULL , fix_to_flt, fix_to_str},
|
||||
{flt_to_int, flt_to_fix, NULL , flt_to_str},
|
||||
{str_to_int, str_to_fix, str_to_flt, NULL }
|
||||
};
|
||||
|
||||
Value cast(Tag type, Value b){
|
||||
if(type.type == b.tag.type && type.is_array == b.tag.is_array)
|
||||
return b;
|
||||
if(type.type == T_null || b.tag.type == T_null || type.type == T_fn
|
||||
|| b.tag.type == T_fn || type.is_array || b.tag.is_array){
|
||||
b.tag.type = T_null;
|
||||
return b;
|
||||
}
|
||||
return cast_table[b.tag.type-1][type.type-1](b);
|
||||
}
|
||||
|
||||
// Generic builtins
|
||||
|
||||
Value add(Value a, Value b){
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Add : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Add : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
a.v4B.value += b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
a.v4B.vfl += b.v4B.vfl;
|
||||
break;
|
||||
case T_str:
|
||||
if(a.vstr.len + b.vstr.len > 4){
|
||||
u32 tmp = flisp_alloc(a.vstr.len + b.vstr.len);
|
||||
if(!tmp){
|
||||
a.tag = ntag;
|
||||
break;
|
||||
}
|
||||
a.vstr.pos = tmp;
|
||||
char *nstr = get_addr(tmp);
|
||||
if(a.vstr.len > 4)
|
||||
memcpy(nstr, get_addr(a.vstr.pos), a.vstr.len);
|
||||
else
|
||||
memcpy(nstr, a.vstr.str, a.vstr.len);
|
||||
if(b.vstr.len > 4)
|
||||
memcpy(nstr+a.vstr.len, get_addr(b.vstr.pos), b.vstr.len);
|
||||
else
|
||||
memcpy(nstr+a.vstr.len, b.vstr.str, b.vstr.len);
|
||||
}
|
||||
else {
|
||||
for(int i = 0; i < b.vstr.len; i++)
|
||||
a.vstr.str[a.vstr.len + i] = b.vstr.str[i];
|
||||
}
|
||||
a.vstr.len += b.vstr.len;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Add : Invalid types");
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
Value sub(Value a, Value b){
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Sub : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Sub : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
a.v4B.value -= b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
a.v4B.vfl -= b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Sub : Invalid types");
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
Value mul(Value a, Value b){
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Mul : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Mul : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
a.v4B.value *= b.v4B.value;
|
||||
break;
|
||||
case T_fix:
|
||||
a.v4B.value = fmul(a.v4B.value, b.v4B.value);
|
||||
break;
|
||||
case T_float:
|
||||
a.v4B.vfl *= b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Mul : Invalid types");
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
Value divv(Value a, Value b){
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Div : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Div : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
a.v4B.value /= b.v4B.value;
|
||||
break;
|
||||
case T_fix:
|
||||
a.v4B.value = fdiv(a.v4B.value, b.v4B.value);
|
||||
break;
|
||||
case T_float:
|
||||
a.v4B.vfl /= b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Div : Invalid types");
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
Value mod(Value a, Value b){
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Mod : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Mod : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
a.v4B.value /= b.v4B.value;
|
||||
break;
|
||||
case T_fix:
|
||||
a.v4B.value = fdiv(a.v4B.value, b.v4B.value);
|
||||
break;
|
||||
case T_float:
|
||||
a.v4B.vfl = (int)a.v4B.vfl % (int)b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Mod : Invalid types");
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
Value sml(Value a, Value b){
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Sml : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Sml : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
returnv.v4B.value = a.v4B.value < b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
returnv.v4B.value = a.v4B.vfl < b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Sml : Invalid types");
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value sml_eq(Value a, Value b){
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Sml_eq : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Sml_eq : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
returnv.v4B.value = a.v4B.value <= b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
returnv.v4B.value = a.v4B.vfl <= b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Sml_eq : Invalid types");
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value eq(Value a, Value b){
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Eq : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Eq : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
returnv.v4B.value = a.v4B.value == b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
returnv.v4B.value = fabs(a.v4B.vfl-b.v4B.vfl) > FL_EPSILON;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Eq : Invalid types");
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value gt_eq(Value a, Value b){
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Gt_eq : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Gt_eq : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
returnv.v4B.value = a.v4B.value >= b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
returnv.v4B.value = a.v4B.vfl >= b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Gt_eq : Invalid types");
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value gt(Value a, Value b){
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
if(a.tag.is_array || b.tag.is_array)
|
||||
runtime_err("Gt : Invalid types");
|
||||
if(a.tag.type != b.tag.type)
|
||||
runtime_err("Gt : Types do not match");
|
||||
switch(a.tag.type){
|
||||
case T_int:
|
||||
case T_fix:
|
||||
returnv.v4B.value = a.v4B.value > b.v4B.value;
|
||||
break;
|
||||
case T_float:
|
||||
returnv.v4B.value = a.v4B.vfl > b.v4B.vfl;
|
||||
break;
|
||||
default:
|
||||
runtime_err("Gt : Invalid types");
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value not(Value a){
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
returnv.v4B.value = !evaluate(a);
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value and(Value a, Value b){
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
returnv.v4B.value = evaluate(a) && evaluate(b);
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value or(Value a, Value b){
|
||||
Value returnv;
|
||||
returnv.tag = (Tag){.is_array=0,.type=T_int};
|
||||
returnv.v4B.value = evaluate(a) || evaluate(b);
|
||||
return returnv;
|
||||
}
|
||||
|
||||
Value len(Value a){
|
||||
|
||||
}
|
||||
|
||||
Value push(Value a, Value b){
|
||||
|
||||
}
|
||||
|
||||
Value pop(Value a, Value b){
|
||||
|
||||
}
|
||||
|
||||
Value fl_write(Value a){
|
||||
char *nstr;
|
||||
switch(a.tag.type){
|
||||
case T_null:
|
||||
case T_any:
|
||||
printf("null");
|
||||
break;
|
||||
case T_int:
|
||||
printf("%d",a.v4B.value);
|
||||
break;
|
||||
case T_fix:
|
||||
printf("%f",f2float(a.v4B.value));
|
||||
break;
|
||||
case T_float:
|
||||
printf("%f",a.v4B.vfl);
|
||||
break;
|
||||
case T_str:
|
||||
nstr = malloc(a.vstr.len+1);
|
||||
if(a.vstr.len > 4){
|
||||
char *str = get_addr(a.vstr.pos);
|
||||
memcpy(nstr, str, a.vstr.len);
|
||||
}
|
||||
else{
|
||||
memcpy(nstr, a.vstr.str, a.vstr.len);
|
||||
}
|
||||
nstr[a.vstr.len] = '\0';
|
||||
printf("%s",nstr);
|
||||
free(nstr);
|
||||
break;
|
||||
case T_fn:
|
||||
printf("<fn @%lx>", (u64)get_fnsig(&a));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (Value){.tag={0,0,T_null}};
|
||||
}
|
||||
|
||||
Value nwline(){
|
||||
printf("\n");
|
||||
return (Value){.tag={0,0,T_null}};
|
||||
}
|
||||
|
||||
const Tag tany = {0,0,T_any};
|
||||
const Tag tint = {0,0,T_int};
|
||||
const Tag tfix = {0,0,T_fix};
|
||||
const Tag tfloat = {0,0,T_float};
|
||||
const Tag tstr = {0,0,T_str};
|
||||
const Tag tfn = {0,0,T_fn};
|
||||
const Tag tvec = {1,0,T_any};
|
||||
|
||||
#define BICAST(x) ((bi_fn_t*)(x))
|
||||
|
||||
FnSig builtins[] = {
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(add)}},
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(sub)}},
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(mul)}},
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(divv)}},
|
||||
{{tany,tany},tany,2,1,{.bi = BICAST(mod)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(sml)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(sml_eq)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(eq)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(gt_eq)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(gt)}},
|
||||
{{tany} ,tint,1,1,{.bi = BICAST(not)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(and)}},
|
||||
{{tany,tany},tint,2,1,{.bi = BICAST(or)}},
|
||||
{{tvec} ,tint,1,1,{.bi = BICAST(len)}},
|
||||
{{tvec,tany},tany,2,1,{.bi = BICAST(push)}},
|
||||
{{tvec,tint},tany,2,1,{.bi = BICAST(pop)}},
|
||||
{{tany} ,tany,1,1,{.bi = BICAST(fl_write)}},
|
||||
{{tany} ,tany,0,1,{.bi = BICAST(nwline)}}
|
||||
};
|
||||
|
||||
char *bi_names[] = {
|
||||
"+",
|
||||
"-",
|
||||
"*",
|
||||
"/",
|
||||
"%",
|
||||
"<",
|
||||
"<=",
|
||||
"=",
|
||||
">=",
|
||||
">",
|
||||
"!",
|
||||
"and",
|
||||
"or",
|
||||
"len",
|
||||
"push",
|
||||
"pop",
|
||||
"write",
|
||||
"newline"
|
||||
};
|
||||
|
||||
void symbol_map_add_bi(HashMap *map){
|
||||
Tag fntag = {0,1,T_fn};
|
||||
for(int i = BI_add; i < BI__end; i++){
|
||||
MapItem *ret = hashmap_insert(map, bi_names[i-BI_add]);
|
||||
ret->type = *((i16*)&fntag);
|
||||
ret->fnsig = &builtins[i-BI_add];
|
||||
ret->is_const = 1;
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "code_defs.h"
|
||||
#include "byte_defs.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
void runtime_err(char *s);
|
||||
|
||||
int evaluate(Value val);
|
||||
|
||||
|
||||
int alloc_init();
|
||||
|
||||
void alloc_clean();
|
||||
|
||||
// All internal allocator memory is guaranteed to be free range
|
||||
u32 flisp_alloc(u32 size);
|
||||
|
||||
u32 flisp_realloc(u32 pos, u32 size);
|
||||
|
||||
void flisp_free(u32 pos);
|
||||
|
||||
void *get_addr(u32 pos);
|
||||
|
||||
|
||||
Value is(Tag tag, Value b);
|
||||
|
||||
Value cast(Tag tag, Value b);
|
||||
|
||||
// Makes a copy of the string
|
||||
// If len < 0, will copy up to a '\0'
|
||||
Value str_to_val(char *str, i32 len);
|
||||
void clean_strval(Value str);
|
||||
|
||||
void symbol_map_add_bi(HashMap *map);
|
11
src/fixed.h
11
src/fixed.h
|
@ -1,9 +1,8 @@
|
|||
// ---
|
||||
// fixed: 16:16 fixed-point arithmetic
|
||||
// ---
|
||||
// Comes from https://gitea.planet-casio.com/Slyvtt/OutRun/
|
||||
// Under it's own license
|
||||
|
||||
//---
|
||||
// fixed: 16:16 fixed-point arithmetic
|
||||
//---
|
||||
//vient de https://gitea.planet-casio.com/Slyvtt/OutRun/src/branch/master/src
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
|
61
src/hash.c
61
src/hash.c
|
@ -1,22 +1,3 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
@ -31,18 +12,12 @@ int heap_hashmap(HashMap *map, i32 size){
|
|||
map->curr_len = size;
|
||||
map->buffer = malloc(sizeof(MapItem)*size);
|
||||
map->bit_free = malloc(sizeof(u32)*size/32);
|
||||
map->item_n = 0;
|
||||
#if LOG
|
||||
printf("Hashmap alloc : %ldKiB\n",
|
||||
(sizeof(MapItem)*size + sizeof(u32)*size/32)/1024);
|
||||
#endif
|
||||
|
||||
if(!map->buffer || !map->bit_free)
|
||||
return 1;
|
||||
|
||||
memset(map->bit_free, 0, sizeof(u32)*size/32);
|
||||
memset(map->buffer, 0, sizeof(MapItem)*size);
|
||||
for(int i = 0; i < size; i++)
|
||||
map->buffer[i].id = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -98,8 +73,7 @@ MapItem *hashmap_insert(HashMap *map, char *str){
|
|||
|
||||
if(!map->bit_free[hsh/32]){
|
||||
map->buffer[hsh].hash = hsh;
|
||||
map->buffer[hsh].id = map->curr_id++;
|
||||
strncpy(map->buffer[hsh].str, str, 36);
|
||||
strncpy(map->buffer[hsh].str, str, 32);
|
||||
set_bit(map->bit_free, hsh);
|
||||
map->item_n++;
|
||||
return &map->buffer[hsh];
|
||||
|
@ -120,8 +94,7 @@ MapItem *hashmap_insert(HashMap *map, char *str){
|
|||
|
||||
if(!taken){
|
||||
map->buffer[pos].hash = hsh;
|
||||
map->buffer[pos].id = map->curr_id++;
|
||||
strncpy(map->buffer[pos].str, str, 36);
|
||||
strncpy(map->buffer[pos].str, str, 32);
|
||||
set_bit(map->bit_free, hsh);
|
||||
map->item_n++;
|
||||
return &map->buffer[pos];
|
||||
|
@ -138,7 +111,7 @@ MapItem *hashmap_get(HashMap *map, char *str){
|
|||
i32 c_hash = map->buffer[pos].hash;
|
||||
match = c_hash == fhash;
|
||||
if(match)
|
||||
match = !strncmp(str,map->buffer[pos].str,36);
|
||||
match = !strncmp(str,map->buffer[pos].str,32);
|
||||
pos++;
|
||||
} while(!match && pos < map->curr_len && pos-fhash < RELOCATE_TRY_MAX);
|
||||
pos--;
|
||||
|
@ -149,29 +122,3 @@ MapItem *hashmap_get(HashMap *map, char *str){
|
|||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hashmap_remove(HashMap *map, char *str){
|
||||
MapItem *ret = hashmap_get(map, str);
|
||||
if(!ret)
|
||||
return;
|
||||
// Erase the existance of the entry
|
||||
// (Literally 1984)
|
||||
memset(ret, 0, sizeof(MapItem));
|
||||
}
|
||||
|
||||
int cmp_mapitem_id(const void *_a, const void *_b){
|
||||
const MapItem *a = _a;
|
||||
const MapItem *b = _b;
|
||||
return b->id - a->id;
|
||||
}
|
||||
|
||||
void hashmap_remove_id(HashMap *map, i32 id){
|
||||
i32 pos = 0;
|
||||
int found = 0;
|
||||
// TODO : Replace with bsearch again
|
||||
for(int i = 0; i < map->curr_len && !found; i++){
|
||||
found = map->buffer[pos++].id == id;
|
||||
}
|
||||
if(found)
|
||||
memset(&map->buffer[--pos], 0, sizeof(MapItem));
|
||||
}
|
||||
|
|
42
src/hash.h
42
src/hash.h
|
@ -1,22 +1,3 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "types.h"
|
||||
|
@ -24,29 +5,25 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define HASH_NULL 0x7FFFFF
|
||||
#define HASH_NULL 0xFFFFFF
|
||||
|
||||
#define RELOCATE_TRY_MAX 32
|
||||
|
||||
typedef struct {
|
||||
|
||||
union {
|
||||
i32 id;
|
||||
void *fnsig;
|
||||
};
|
||||
uint hash : 23;
|
||||
uint is_const : 1;
|
||||
u16 type;
|
||||
char str[36];
|
||||
i32 hash; // Hashs are internally 24bit for bytecode ops
|
||||
char str[32];
|
||||
i32 id;
|
||||
void *fnsig;
|
||||
i32 type;
|
||||
|
||||
} PACKED NOPOS MapItem;
|
||||
} MapItem;
|
||||
|
||||
typedef struct {
|
||||
|
||||
MapItem *buffer;
|
||||
u32 *bit_free; // Bit map to track usage
|
||||
i32 curr_len; // In items
|
||||
i32 curr_id;
|
||||
i32 item_n;
|
||||
i32 is_heap; // TODO
|
||||
|
||||
|
@ -67,8 +44,3 @@ MapItem *hashmap_insert(HashMap *map, char *str);
|
|||
|
||||
// Returns NULL if error/not found
|
||||
MapItem *hashmap_get(HashMap *map, char *str);
|
||||
|
||||
void hashmap_remove(HashMap *map, char *str);
|
||||
|
||||
void hashmap_remove_id(HashMap *map, i32 id);
|
||||
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "fixed.h"
|
||||
#include "hash.h"
|
||||
#include "types.h"
|
||||
#include "config.h"
|
||||
#include "code_defs.h"
|
||||
#include "byte_defs.h"
|
||||
#include "exec_common.h"
|
||||
|
||||
Value vars[SYMBOL_MAP_S];
|
||||
|
||||
Value execute(Statement *stat);
|
||||
|
||||
void assign(Value *dst, Value src){
|
||||
#if LOG
|
||||
printf("Assign : %d -> %d\n", src.tag.type, dst->tag.type);
|
||||
#endif
|
||||
if(dst->tag.is_array != src.tag.is_array)
|
||||
runtime_err("Invalid assignement");
|
||||
if(dst->tag.type == src.tag.type || !dst->tag.is_strong
|
||||
|| dst->tag.type == T_any)
|
||||
*dst = src;
|
||||
else{
|
||||
runtime_err("Invalid assignement");
|
||||
}
|
||||
}
|
||||
|
||||
Value fncall(FnSig *fn, Statement **params){
|
||||
Value returnv = {.tag = {0,0,T_null}};
|
||||
if(fn->is_builtin){
|
||||
switch(fn->n_param){
|
||||
case 0:
|
||||
returnv = fn->bi();
|
||||
break;
|
||||
case 1:{
|
||||
Value (*fn1)(Value) = (void*)fn->bi;
|
||||
returnv = fn1(execute(params[0]));
|
||||
break;
|
||||
}
|
||||
case 2:{
|
||||
Value (*fn2)(Value,Value) = (void*)fn->bi;
|
||||
returnv = fn2(execute(params[0]),execute(params[1]));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
runtime_err("Call to builtin with >2 params");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef INTERPR
|
||||
returnv = execute(fn->stmt);
|
||||
#else
|
||||
#warning "fncall not implemented for compiler"
|
||||
#endif
|
||||
}
|
||||
return returnv;
|
||||
}
|
||||
|
||||
void init_exec(){
|
||||
|
||||
}
|
||||
|
||||
Value execute(Statement *stat){
|
||||
Value returnv = {.tag = {0,0,T_null}};
|
||||
switch(stat->type){
|
||||
case ST_Varuse:
|
||||
if(vars[stat->var_id].tag.type == T_fn){
|
||||
Statement **params = NULL;
|
||||
FnSig *fn = get_fnsig(&vars[stat->var_id]);
|
||||
if(fn->n_param)
|
||||
params = (Statement**)((Statement*)stat->children[0])->children;
|
||||
fncall(fn, params);
|
||||
}
|
||||
else
|
||||
runtime_err("Calling invalid type");
|
||||
break;
|
||||
case ST_None:
|
||||
runtime_err("ST_None to process !");
|
||||
break;
|
||||
case ST_Const:
|
||||
returnv = stat->cons;
|
||||
break;
|
||||
case ST_Var:
|
||||
returnv = vars[stat->var_id];
|
||||
break;
|
||||
case ST_Block:
|
||||
for(int i = 0; i < stat->child_n; i++){
|
||||
returnv = execute(stat->children[i]);
|
||||
}
|
||||
break;
|
||||
case ST_Set:
|
||||
assign(&vars[stat->var_id], execute(stat->children[0]));
|
||||
break;
|
||||
case BI_var:
|
||||
case BI_let:
|
||||
// Init the relevant value for correct type checks
|
||||
#if LOG
|
||||
printf("var : %d\n", stat->var_type.type);
|
||||
#endif
|
||||
vars[stat->var_id].tag = stat->var_type;
|
||||
if(stat->child_n)
|
||||
assign(&vars[stat->var_id],execute(stat->children[0]));
|
||||
break;
|
||||
case BI_if:
|
||||
if(evaluate(execute(stat->children[0])))
|
||||
execute(stat->children[1]);
|
||||
else {
|
||||
if(stat->els)
|
||||
execute(((Statement*)stat->els)->children[0]);
|
||||
}
|
||||
case BI_else:
|
||||
break;
|
||||
case BI_while:
|
||||
while(evaluate(execute(stat->children[0])))
|
||||
execute(stat->children[1]);
|
||||
break;
|
||||
case BI_fn:
|
||||
case BI_import:
|
||||
break;
|
||||
case BI_is:
|
||||
returnv = is(stat->var_type, execute(stat->children[0]));
|
||||
break;
|
||||
case BI_cast:
|
||||
returnv = cast(stat->var_type, execute(stat->children[0]));
|
||||
break;
|
||||
case ST_Call:{
|
||||
FnSig *fn = stat->func;
|
||||
Statement **params = NULL;
|
||||
if(fn->n_param)
|
||||
params = (Statement**)((Statement*)stat->children[0])->children;
|
||||
returnv = fncall(fn, params);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return returnv;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "code_defs.h"
|
||||
#include "byte_defs.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
Value execute(Statement *stat);
|
69
src/main.c
69
src/main.c
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "tests.h"
|
||||
#include "code_defs.h"
|
||||
#include "parser.h"
|
||||
#include "interpreter.h"
|
||||
#include "exec_common.h"
|
||||
|
||||
#include "y.tab.h"
|
||||
|
||||
extern FILE *yyin;
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
i32 fpos = 1;
|
||||
|
||||
if(argc > 1){
|
||||
if(!strcmp(argv[1], "--tests")){
|
||||
fpos++;
|
||||
do_tests();
|
||||
}
|
||||
}
|
||||
if(argc > fpos) {
|
||||
yyin = fopen(argv[fpos], "r");
|
||||
if(!yyin){
|
||||
fprintf(stderr,"Failed to open file \"%s\"", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("fLisp interactive env - v0.1\nFcalva 2025\n");
|
||||
printf("Under the terms of the GPL v2.0 license\n");
|
||||
yyin = stdin;
|
||||
}
|
||||
|
||||
alloc_init();
|
||||
|
||||
make_stack();
|
||||
yyparse();
|
||||
free_stack();
|
||||
|
||||
alloc_clean();
|
||||
|
||||
fclose(yyin);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,22 +1,3 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -24,10 +5,8 @@
|
|||
#include <assert.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "config.h"
|
||||
#include "byte_defs.h"
|
||||
#include "code_defs.h"
|
||||
#include "exec_common.h"
|
||||
#include "parser.h"
|
||||
#include "hash.h"
|
||||
|
||||
|
@ -35,61 +14,17 @@ ASTStack *stack;
|
|||
|
||||
void yyerror(char *s);
|
||||
|
||||
Tag ntag = {0,0,T_null};
|
||||
|
||||
Tag atag = {0,0,T_any};
|
||||
|
||||
int make_stack(){
|
||||
stack = malloc(sizeof(ASTStack)+sizeof(Statement)*2048);
|
||||
#if LOG
|
||||
printf("AST alloc : %ld KiB\n",
|
||||
(sizeof(ASTStack)+sizeof(Statement)*2048)/1024);
|
||||
#endif
|
||||
if(!stack)
|
||||
return 1;
|
||||
if(heap_hashmap(&stack->symbol_map, SYMBOL_MAP_S))
|
||||
return 1;
|
||||
stack->funcs = NULL;
|
||||
stack->fn_n = 0;
|
||||
stack->stack_size = 2048;
|
||||
symbol_map_add_bi(&stack->symbol_map);
|
||||
stack->scope_id = 1;
|
||||
stack->curr_scope = 1;
|
||||
stack->curr_statement = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_stack(){
|
||||
for(int i = 0; i < stack->curr_statement; i++){
|
||||
Statement *stat = &stack->statements[i];
|
||||
if(stat->child_n)
|
||||
free(stat->children);
|
||||
}
|
||||
free(stack->funcs);
|
||||
free_hashmap(&stack->symbol_map);
|
||||
free(stack);
|
||||
}
|
||||
|
||||
void clean_name(char *name){
|
||||
i32 len = strcspn(name, " \t\n)");
|
||||
name[len] = '\0';
|
||||
}
|
||||
|
||||
Statement *get_statement(){
|
||||
if(stack->curr_statement >= stack->stack_size){
|
||||
stack = realloc(stack, sizeof(ASTStack)+sizeof(Statement)*(stack->stack_size+2048));
|
||||
if(!stack)
|
||||
yyerror("Failed to extend stack");
|
||||
stack->stack_size += 2048;
|
||||
}
|
||||
return &stack->statements[stack->curr_statement++];
|
||||
}
|
||||
|
||||
i32 curr_scope(){
|
||||
return stack->scope_stack[stack->curr_scope];
|
||||
}
|
||||
|
||||
char *bi_type_names[6] = {
|
||||
"",
|
||||
"int",
|
||||
|
@ -100,97 +35,45 @@ char *bi_type_names[6] = {
|
|||
};
|
||||
|
||||
Tag get_type(char *str){
|
||||
puts("get_type");
|
||||
for(int i = 1; i < 6; i++){
|
||||
if(!strcmp(bi_type_names[i], str))
|
||||
return (Tag){0,1,i};
|
||||
return (Tag){0, i};
|
||||
}
|
||||
return (Tag){0,0,0};
|
||||
return (Tag){0, 0};
|
||||
}
|
||||
|
||||
Statement *make_iconst(i32 val){
|
||||
Statement *stat = get_statement();
|
||||
puts("make_iconst");
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
stat->type = ST_Const;
|
||||
stat->cons = (Value){{.v4B = {.value=val}},{.is_array = 0, .type = T_int}};
|
||||
stat->is_const = 1;
|
||||
stat->cons = (Value){{.v4B = {val}},{.is_array = 0, .type = T_int}};
|
||||
stat->child_n = 0;
|
||||
return stat;
|
||||
}
|
||||
|
||||
Statement *make_fconst(float val){
|
||||
Statement *stat = get_statement();
|
||||
stat->type = ST_Const;
|
||||
stat->cons = (Value){{.v4B = {.vfl=val}},{.is_array=0,.type=T_float}};
|
||||
stat->is_const = 1;
|
||||
stat->child_n = 0;
|
||||
return stat;
|
||||
}
|
||||
|
||||
Statement *make_strconst(char *str){
|
||||
Statement *stat = get_statement();
|
||||
stat->type = ST_Const;
|
||||
stat->is_const = 1;
|
||||
i32 len = strcspn(str, "\"");
|
||||
stat->cons = str_to_val(str, len);
|
||||
return stat;
|
||||
}
|
||||
|
||||
// 3 digit "Base64" scope id + { (invalid identifier char) + name
|
||||
void mangle_name(char *dst, i32 scope, char *name){
|
||||
// Scope 0 is global so we just return the name
|
||||
if(!scope)
|
||||
return;
|
||||
for(int i = 0; i < 3; i++){
|
||||
dst[i] = (scope & 63) + ' ';
|
||||
scope >>= 6;
|
||||
}
|
||||
dst[3] = '{';
|
||||
strncpy(&dst[4], name, 32);
|
||||
}
|
||||
|
||||
Statement *declare(i32 type, Tag vtype, char *name, Statement *assign){
|
||||
char tmpbuf[36];
|
||||
|
||||
clean_name(name);
|
||||
Statement *stat = get_statement();
|
||||
Statement *declare(i32 type, Tag vtype, char *name){
|
||||
puts("declare");
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
stat->type = type;
|
||||
if(type == BI_let){
|
||||
mangle_name(tmpbuf, curr_scope(), name);
|
||||
name = tmpbuf;
|
||||
}
|
||||
|
||||
if(hashmap_get(&stack->symbol_map, name))
|
||||
if(hashmap_get(&stack->symbol_map, name)){
|
||||
yyerror("Redeclaring existing identifier");
|
||||
}
|
||||
MapItem *ret = hashmap_insert(&stack->symbol_map, name);
|
||||
ret->type = *((i16*)&vtype);
|
||||
#if LOG
|
||||
printf("declare : id : %d\n", ret->id);
|
||||
#endif
|
||||
ret->type = *((i32*)&vtype);
|
||||
stat->var_id = ret->id;
|
||||
stat->var_type = vtype;
|
||||
if(assign){
|
||||
stat->child_n = 1;
|
||||
stat->children = malloc(sizeof(void*));
|
||||
if(!stat->children)
|
||||
yyerror("Failed to alloc");
|
||||
stat->children[0] = assign;
|
||||
}
|
||||
else
|
||||
stat->child_n = 0;
|
||||
stat->child_n = 0;
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
Statement *variable_get(char *name){
|
||||
clean_name(name);
|
||||
Statement *stat = get_statement();
|
||||
puts("variable_get");
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
MapItem *ret = hashmap_get(&stack->symbol_map, name);
|
||||
if(!ret){
|
||||
char tmpbuf[36];
|
||||
mangle_name(tmpbuf, curr_scope(), name);
|
||||
ret = hashmap_get(&stack->symbol_map, tmpbuf);
|
||||
if(!ret)
|
||||
yyerror("Undefined identifier");
|
||||
}
|
||||
if(!ret)
|
||||
yyerror("Undefined identifier");
|
||||
stat->type = ST_Var;
|
||||
stat->var_id = ret->id;
|
||||
stat->var_type = *((Tag*)&ret->type);
|
||||
|
@ -198,151 +81,70 @@ Statement *variable_get(char *name){
|
|||
return stat;
|
||||
}
|
||||
|
||||
Statement *set_var(char *name, Statement *expr){
|
||||
clean_name(name);
|
||||
Statement *stat = get_statement();
|
||||
MapItem *ret = hashmap_get(&stack->symbol_map, name);
|
||||
if(!ret)
|
||||
yyerror("Undefined indentifier");
|
||||
stat->type = ST_Set;
|
||||
stat->var_id = ret->id;
|
||||
stat->var_type = *((Tag*)&ret->type);
|
||||
stat->children = malloc(sizeof(void*));
|
||||
if(!stat->children)
|
||||
yyerror("Failed to alloc");
|
||||
stat->children[0] = expr;
|
||||
return stat;
|
||||
}
|
||||
|
||||
Statement *make_block(Statement *first){
|
||||
Statement *stat = get_statement();
|
||||
puts("make_block");
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
stat->type = ST_Block;
|
||||
stat->children = malloc(sizeof(void*));
|
||||
stat->children[0] = first;
|
||||
first->parent = stat;
|
||||
stat->child_n = 1;
|
||||
return stat;
|
||||
}
|
||||
|
||||
Statement *add_block(Statement *block, Statement *add){
|
||||
puts("add_block");
|
||||
block->children = realloc(block->children, sizeof(void*)*(block->child_n+1));
|
||||
block->children[block->child_n++] = add;
|
||||
add->parent = block;
|
||||
return block;
|
||||
}
|
||||
|
||||
FnSig assign_sig = {.n_param = 1};
|
||||
|
||||
Statement *make_operation(i32 type, Tag vtype, char *name, i32 nparam, ...){
|
||||
Statement *stat = get_statement();
|
||||
FnSig bi_sig[] = {
|
||||
|
||||
};
|
||||
|
||||
Statement *make_operation(i32 type, i32 extrainf, char *name, i32 nparam,
|
||||
Statement *param, ...){
|
||||
printf("make_operation: ", name);
|
||||
Statement *stat = &stack->statements[stack->curr_statement++];
|
||||
if(nparam)
|
||||
stat->children = malloc(sizeof(void*)*nparam);
|
||||
stat->child_n = 0;
|
||||
|
||||
va_list prm;
|
||||
va_start(prm, nparam);
|
||||
Statement *param = va_arg(prm, Statement*);
|
||||
|
||||
if(!type || type == ST_Call){
|
||||
i32 len = strcspn(name, " \t\n()");
|
||||
name[len] = '\0';
|
||||
#if LOG
|
||||
printf("name : \"%s\"\n",name);
|
||||
#endif
|
||||
MapItem *ret = hashmap_get(&stack->symbol_map, name);
|
||||
FnSig *fnsig = NULL;
|
||||
if(!type){
|
||||
i32 len = strcspn(name, " \t\n");
|
||||
char *name2 = strndup(name, len);
|
||||
puts(name2);
|
||||
MapItem *ret = hashmap_get(&stack->symbol_map, name2);
|
||||
if(!ret)
|
||||
yyerror("Undefined identifer");
|
||||
#if LOG
|
||||
printf("id : %d\n", ret->id);
|
||||
#endif
|
||||
if(ret->is_const && ((Tag*)&ret->type)->type == T_fn){
|
||||
type = ST_Call;
|
||||
stat->func = ret->fnsig;
|
||||
if(nparam > 1 && ret->type != T_fn)
|
||||
yyerror("Too many parameters to assignement");
|
||||
if(ret->type != T_fn){
|
||||
type = BI_assign;
|
||||
assign_sig.params[0] = *((Tag*)&ret->type);
|
||||
fnsig = &assign_sig;
|
||||
}
|
||||
else {
|
||||
type = ST_Varuse;
|
||||
stat->var_id = ret->id;
|
||||
fnsig = ret->fnsig;
|
||||
}
|
||||
if(nparam > fnsig->n_param)
|
||||
yyerror("Too many parameters to function");
|
||||
}
|
||||
if(type == BI_is || type == BI_cast)
|
||||
stat->var_type = vtype;
|
||||
if(type == BI_if)
|
||||
stat->els = NULL;
|
||||
|
||||
stat->type = type;
|
||||
|
||||
if(nparam){
|
||||
stat->children[stat->child_n++] = param;
|
||||
param->parent = stat;
|
||||
}
|
||||
// TODO : Type checks
|
||||
for(int i = 1; i < nparam; i++){
|
||||
va_list prm;
|
||||
va_start(prm, param);
|
||||
for(int i = 0; i < fnsig->n_param; i++){
|
||||
Statement *prm_n = va_arg(prm, Statement*);
|
||||
stat->children[stat->child_n++] = prm_n;
|
||||
prm_n->parent = stat;
|
||||
stack->curr_statement++;
|
||||
}
|
||||
va_end(prm);
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
void push_scope(){
|
||||
#if LOG
|
||||
printf("push_scope %d\n", stack->scope_id);
|
||||
#endif
|
||||
if(stack->curr_scope >= 256)
|
||||
yyerror("Scopes are too deep");
|
||||
stack->scope_stack[stack->curr_scope++] = stack->scope_id++;
|
||||
}
|
||||
|
||||
void pop_scope(){
|
||||
stack->curr_scope--;
|
||||
#if LOG
|
||||
printf("pop_scope %d\n", stack->scope_stack[stack->curr_scope]);
|
||||
#endif
|
||||
if(stack->curr_scope < 0)
|
||||
yyerror("Weird scope error");
|
||||
}
|
||||
|
||||
FnArgs *make_fnargs(char *name, Tag type){
|
||||
#if LOG
|
||||
printf("fnargs : %s\n", name);
|
||||
#endif
|
||||
FnArgs *args = malloc(sizeof(FnArgs));
|
||||
if(!args)
|
||||
yyerror("alloc error");
|
||||
args->n_args = 1;
|
||||
// TODO
|
||||
args->param_decl[0] = NULL;
|
||||
args->types[0] = type;
|
||||
return args;
|
||||
}
|
||||
|
||||
FnArgs *add_fnargs(FnArgs *args, char *name, Tag type){
|
||||
#if LOG
|
||||
printf("fnargs : %s\n", name);
|
||||
#endif
|
||||
if(args->n_args >= 9)
|
||||
yyerror("Too many args to func");
|
||||
|
||||
Statement *decl = declare(BI_let, type, name, NULL);
|
||||
args->param_decl[args->n_args] = decl;
|
||||
args->types[args->n_args++] = type;
|
||||
return args;
|
||||
}
|
||||
|
||||
Statement *make_function(FnArgs *fn_args, Statement *statements){
|
||||
printf("make_function : %s\n", fn_args->names[0]);
|
||||
Statement *stat = get_statement();
|
||||
stat->type = BI_fn;
|
||||
|
||||
|
||||
|
||||
free(fn_args);
|
||||
return stat;
|
||||
}
|
||||
|
||||
// TODO
|
||||
void set_entry_point(Statement *statement){
|
||||
printf("set_entry_point\n");
|
||||
}
|
||||
|
|
47
src/parser.h
47
src/parser.h
|
@ -1,65 +1,30 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "byte_defs.h"
|
||||
#include "code_defs.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
|
||||
// 0 is function name/output type
|
||||
Statement *param_decl[9];
|
||||
Tag types[9];
|
||||
i32 n_args;
|
||||
|
||||
} FnArgs;
|
||||
|
||||
void yyerror(char *s);
|
||||
|
||||
int make_stack();
|
||||
|
||||
void free_stack();
|
||||
|
||||
Tag get_type(char *str);
|
||||
|
||||
Statement *make_iconst(i32 val);
|
||||
|
||||
//TODO
|
||||
Statement *make_fconst(float val);
|
||||
Statement *make_strconst(char *str);
|
||||
|
||||
Statement *declare(i32 type, Tag vtype, char *name, Statement *assign);
|
||||
Statement *declare(i32 type, Tag vtype, char *name);
|
||||
|
||||
Statement *variable_get(char *name);
|
||||
Statement *set_var(char *name, Statement *expr);
|
||||
|
||||
Statement *make_block(Statement *first);
|
||||
|
||||
Statement *add_block(Statement *block, Statement *add);
|
||||
|
||||
Statement *make_operation(i32 type, Tag vtype, char *str, i32 nparam, ...);
|
||||
|
||||
void push_scope();
|
||||
void pop_scope();
|
||||
|
||||
FnArgs *make_fnargs(char *name, Tag type);
|
||||
FnArgs *add_fnargs(FnArgs *args, char *name, Tag type);
|
||||
|
||||
Statement *make_function(FnArgs *fn_args, Statement *statements);
|
||||
Statement *make_operation(i32 type, i32 extainf, char *str, i32 nparam,
|
||||
Statement *param, ...);
|
||||
|
||||
void set_entry_point(Statement *statement);
|
||||
|
|
45
src/parser.l
45
src/parser.l
|
@ -1,23 +1,4 @@
|
|||
%{
|
||||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "code_defs.h"
|
||||
|
@ -28,7 +9,6 @@
|
|||
|
||||
%%
|
||||
|
||||
#.*\n ;
|
||||
|
||||
":vec" return VEC;
|
||||
|
||||
|
@ -39,38 +19,25 @@
|
|||
|
||||
"if" return IF;
|
||||
"else" return ELSE;
|
||||
"while" return WHILE;
|
||||
"fn" {
|
||||
push_scope();
|
||||
return FN;
|
||||
}
|
||||
"fn" return FN;
|
||||
"var" return VAR;
|
||||
"let" return LET;
|
||||
"block" return BLOCK;
|
||||
"is" return IS;
|
||||
"set" return SET;
|
||||
|
||||
\"[^"\n]*["\n] {
|
||||
yylval.st = make_strconst(yytext+1);
|
||||
return CST;
|
||||
}
|
||||
|
||||
[-+*/%<=>!a-zA-Z]+ {
|
||||
[-+*/%a-zA-Z]+ {
|
||||
yylval.str = yytext;
|
||||
return G_IDENT;
|
||||
}
|
||||
|
||||
[0-9]*"."[0-9]+ {
|
||||
yylval.st = make_fconst(atof(yytext));
|
||||
return CST;
|
||||
}
|
||||
|
||||
[0-9]+ {
|
||||
yylval.st = make_iconst(atoi(yytext));
|
||||
return CST;
|
||||
}
|
||||
|
||||
[();] return *yytext;
|
||||
[()<=>!] return *yytext;
|
||||
|
||||
">=" return GTEQ;
|
||||
"<=" return SMEQ;
|
||||
|
||||
[ \t\n]+ ;
|
||||
|
||||
|
|
134
src/parser.y
134
src/parser.y
|
@ -1,72 +1,38 @@
|
|||
%{
|
||||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "tests.h"
|
||||
#include "code_defs.h"
|
||||
#include "parser.h"
|
||||
#include "interpreter.h"
|
||||
#include "exec_common.h"
|
||||
|
||||
int yylex();
|
||||
extern void print_ast(Statement *base);
|
||||
%}
|
||||
|
||||
%union {
|
||||
char *str;
|
||||
Statement *st;
|
||||
Tag tag;
|
||||
FnArgs *args;
|
||||
}
|
||||
|
||||
%token <str> G_IDENT
|
||||
%token <str> TYPE_U
|
||||
%token <str> G_IDENT TYPE_U
|
||||
%token VEC
|
||||
%token VAR
|
||||
%token LET
|
||||
%token SET
|
||||
%token IF
|
||||
%token ELSE
|
||||
%token WHILE
|
||||
%token FN
|
||||
%token GTEQ
|
||||
%token SMEQ
|
||||
%token BLOCK
|
||||
%token IS
|
||||
%token <st> CST
|
||||
|
||||
%type <st> expr expr_list
|
||||
%type <st> stmt stmt_list
|
||||
%type <tag> type
|
||||
%type <args> fn_args
|
||||
|
||||
%%
|
||||
|
||||
program:
|
||||
expr_list ';'
|
||||
{print_ast($1);execute($1);}
|
||||
| expr_list YYEOF
|
||||
{print_ast($1);execute($1);}
|
||||
| program expr_list ';'
|
||||
{print_ast($2);execute($2);}
|
||||
stmt_list '.' {set_entry_point($1); exit(0); }
|
||||
;
|
||||
|
||||
type:
|
||||
|
@ -80,69 +46,55 @@ type:
|
|||
;
|
||||
|
||||
fn_args:
|
||||
G_IDENT
|
||||
{$$ = make_fnargs($1, atag);}
|
||||
| G_IDENT type
|
||||
{$$ = make_fnargs($1, $2);}
|
||||
| fn_args G_IDENT
|
||||
{$$ = add_fnargs($1, $2, atag);}
|
||||
G_IDENT type
|
||||
{}
|
||||
| fn_args G_IDENT type
|
||||
{$$ = add_fnargs($1, $2, $3);}
|
||||
{}
|
||||
;
|
||||
|
||||
expr:
|
||||
stmt:
|
||||
'(' G_IDENT ')'
|
||||
{$$ = make_operation(ST_Call,ntag,$2,0);}
|
||||
| '(' VAR G_IDENT ')'
|
||||
{ $$ = declare(BI_var,atag,$3,NULL);}
|
||||
{$$ = make_operation(ST_Call, 0, $2, 0, NULL);}
|
||||
| '(' VAR G_IDENT ')'
|
||||
{Tag ntag = {0,T_null}; $$ = declare(BI_var,ntag,$3);}
|
||||
| '(' VAR type G_IDENT ')'
|
||||
{$$ = declare(BI_var, $3, $4, NULL);}
|
||||
| '(' VAR G_IDENT expr')'
|
||||
{$$ = declare(BI_var,atag,$3,$4);}
|
||||
| '(' VAR type G_IDENT expr ')'
|
||||
{$$ = declare(BI_var,$3,$4,$5);}
|
||||
| '(' LET G_IDENT ')'
|
||||
{}
|
||||
| '(' LET type G_IDENT ')'
|
||||
{}
|
||||
| '(' LET G_IDENT expr ')'
|
||||
{}
|
||||
| '(' LET type G_IDENT expr ')'
|
||||
{}
|
||||
| '(' SET G_IDENT expr ')'
|
||||
{$$ = set_var($3, $4);}
|
||||
| '(' IF expr expr_list ')'
|
||||
{$$ = make_operation(BI_if, ntag, NULL, 2, $3, $4);}
|
||||
| '(' IF expr expr_list ')' '(' ELSE expr_list ')'
|
||||
{Statement *ifs = make_operation(BI_if, ntag, NULL, 2, $3, $4);
|
||||
Statement *els = make_operation(BI_else, ntag, NULL, 1, $8);
|
||||
ifs->els = els;
|
||||
$$ = add_block(make_block(ifs),els);
|
||||
{$$ = declare(BI_var, $3, $4);}
|
||||
| '(' IF stmt stmt_list ')'
|
||||
{$$ = make_operation(BI_if, 0, NULL, 2, $3, $4);}
|
||||
| '(' IF stmt stmt_list ')' '(' ELSE stmt_list ')'
|
||||
{Statement *st = make_block(make_operation(BI_if, 0, NULL, 2, $3, $4));
|
||||
$$ = add_block(st, make_operation(BI_else, 0, NULL, 1, $8));
|
||||
}
|
||||
| '(' WHILE expr expr_list ')'
|
||||
{$$ = make_operation(BI_while, ntag, NULL, 2, $3, $4);}
|
||||
| '(' FN '(' fn_args ')' expr_list ')'
|
||||
{$$ = make_function($4, $6);
|
||||
pop_scope();
|
||||
}
|
||||
| '(' BLOCK expr_list ')'
|
||||
| '(' WHILE stmt stmt_list ')'
|
||||
{}
|
||||
| '(' FN fn_args stmt_list ')'
|
||||
{}
|
||||
| '(' GTEQ stmt stmt ')'
|
||||
{}
|
||||
| '(' SMEQ stmt stmt ')'
|
||||
{}
|
||||
| '(' '<' stmt stmt ')'
|
||||
{}
|
||||
| '(' '>' stmt stmt ')'
|
||||
{}
|
||||
| '(' '=' stmt stmt ')'
|
||||
{}
|
||||
| '(' '!' stmt ')'
|
||||
{}
|
||||
| '(' BLOCK stmt_list ')'
|
||||
{$$ = $3;}
|
||||
| '(' G_IDENT expr_list ')'
|
||||
{$$ = make_operation(ST_Call, ntag, $2, 1, $3);}
|
||||
| '(' IS type expr ')'
|
||||
{$$ = make_operation(BI_is, $3, NULL, 1, $4);}
|
||||
| '(' type expr ')'
|
||||
{$$ = make_operation(BI_cast, $2, NULL, 1, $3);}
|
||||
| '(' G_IDENT stmt ')'
|
||||
{$$ = make_operation(ST_None, 0, $2, 1, $3);}
|
||||
| G_IDENT
|
||||
{$$ = variable_get($1);}
|
||||
| CST
|
||||
{$$ = $1;}
|
||||
;
|
||||
|
||||
expr_list:
|
||||
expr
|
||||
stmt_list:
|
||||
stmt
|
||||
{$$ = make_block($1);}
|
||||
| expr_list expr
|
||||
| stmt_list stmt
|
||||
{$$ = add_block($1, $2);}
|
||||
;
|
||||
|
||||
|
@ -152,3 +104,9 @@ void yyerror(char *s){
|
|||
fprintf(stderr, "Error : %s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(){
|
||||
make_stack();
|
||||
yyparse();
|
||||
return 0;
|
||||
}
|
||||
|
|
225
src/tests.c
225
src/tests.c
|
@ -1,225 +0,0 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "parser.h"
|
||||
#include "code_defs.h"
|
||||
#include "byte_defs.h"
|
||||
#include "exec_common.h"
|
||||
|
||||
typedef int (test_fun_t)(void);
|
||||
|
||||
HashMap t_hmap;
|
||||
|
||||
int t_heap_hashmap(){
|
||||
return heap_hashmap(&t_hmap,512);
|
||||
}
|
||||
|
||||
int t_hashmap_insert_get(){
|
||||
int err = 0;
|
||||
MapItem *ret = hashmap_insert(&t_hmap, "test");
|
||||
if(!ret)
|
||||
return 1;
|
||||
err += ret->id != 0;
|
||||
ret->type = 69;
|
||||
MapItem *ret2 = hashmap_get(&t_hmap, "test");
|
||||
if(!ret2)
|
||||
return 1;
|
||||
err += ret2->type != 69 || ret2->id != 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int t_hashmap_remove(){
|
||||
int err = 0;
|
||||
hashmap_remove(&t_hmap, "test");
|
||||
MapItem *ret = hashmap_get(&t_hmap, "test");
|
||||
err += !!ret;
|
||||
MapItem *ret2 = hashmap_insert(&t_hmap, "very_verbose_function_i_guess");
|
||||
hashmap_remove_id(&t_hmap, ret2->id);
|
||||
err += !!hashmap_get(&t_hmap, "very_verbose_function_i_guess");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int t_free_hashmap(){
|
||||
free_hashmap(&t_hmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int t_alloc_init(){
|
||||
return alloc_init();
|
||||
}
|
||||
|
||||
int t_flisp_alloc(){
|
||||
int err = 0;
|
||||
u32 pos0 = flisp_alloc(sizeof(u64));
|
||||
u32 pos1 = flisp_alloc(sizeof(u64));
|
||||
err += !pos0 || !pos1;
|
||||
if(err)
|
||||
return 1;
|
||||
err += pos0 == pos1;
|
||||
u64 *ptr0 = get_addr(pos0);
|
||||
u64 *ptr1 = get_addr(pos1);
|
||||
*ptr1 = 0;
|
||||
*ptr0 = 0xFFFFFFFFFFFFFFFF;
|
||||
err += !!*ptr1;
|
||||
flisp_free(pos0);
|
||||
flisp_free(pos1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int t_flisp_realloc(){
|
||||
int err = 0;
|
||||
u8 ref[5] = {1,2,3,4,5};
|
||||
u32 pos0 = flisp_alloc(5);
|
||||
if(!pos0)
|
||||
return 1;
|
||||
u8 *ptr0 = get_addr(pos0);
|
||||
memcpy(ptr0, ref, 5);
|
||||
pos0 = flisp_realloc(pos0, 10);
|
||||
if(!pos0)
|
||||
return 1;
|
||||
ptr0 = get_addr(pos0);
|
||||
err += memcmp(ptr0, ref, 5);
|
||||
flisp_free(pos0);
|
||||
return err;
|
||||
}
|
||||
|
||||
int t_alloc_clean(){
|
||||
alloc_clean();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int t_get_type(){
|
||||
int err = 0;
|
||||
Tag ttag = get_type("int");
|
||||
err += ttag.type != T_int || ttag.is_array;
|
||||
ttag = get_type("fix");
|
||||
err += ttag.type != T_fix || ttag.is_array;
|
||||
return err;
|
||||
}
|
||||
|
||||
int t_make_stack(){
|
||||
return make_stack();
|
||||
}
|
||||
|
||||
int t_make_iconst(){
|
||||
int err = 0;
|
||||
Statement *st = NULL;
|
||||
st = make_iconst(69);
|
||||
if(!st)
|
||||
return 1;
|
||||
err += st->type != ST_Const || !st->is_const || st->child_n;
|
||||
err += st->cons.v4B.value != 69 || st->cons.tag.type != T_int;
|
||||
err += st->cons.tag.is_array;
|
||||
return err;
|
||||
}
|
||||
|
||||
int t_make_fconst(){
|
||||
int err = 0;
|
||||
Statement *st = NULL;
|
||||
st = make_fconst(0.420);
|
||||
if(!st)
|
||||
return 1;
|
||||
err += st->type != ST_Const || !st->is_const || st->child_n;
|
||||
err += st->cons.v4B.vfl != 0.420f || st->cons.tag.type != T_float;
|
||||
err += st->cons.tag.is_array;
|
||||
return err;
|
||||
}
|
||||
|
||||
int t_make_strconst(){
|
||||
int err = 0;
|
||||
Statement *st = NULL;
|
||||
st = make_strconst("Hello world");
|
||||
if(!st)
|
||||
return 1;
|
||||
err += st->type != ST_Const || !st->is_const || st->child_n;
|
||||
err += st->cons.vstr.len != 11 || st->cons.tag.type != T_str;
|
||||
err += strncmp(get_addr(st->cons.vstr.pos), "Hello world", 11);
|
||||
st = make_strconst("Gatt");
|
||||
if(!st)
|
||||
return 1;
|
||||
err += st->type != ST_Const || !st->is_const || st->child_n;
|
||||
err += st->cons.vstr.len != 4 || st->cons.tag.type != T_str;
|
||||
err += strncmp(st->cons.vstr.str, "Gatt", 4);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int t_free_stack(){
|
||||
free_stack();
|
||||
return 0;
|
||||
}
|
||||
|
||||
test_fun_t *tests[] = {
|
||||
t_heap_hashmap,
|
||||
t_hashmap_insert_get,
|
||||
t_hashmap_remove,
|
||||
t_free_hashmap,
|
||||
t_alloc_init,
|
||||
t_flisp_alloc,
|
||||
t_flisp_realloc,
|
||||
t_alloc_clean,
|
||||
t_get_type,
|
||||
t_make_stack,
|
||||
t_make_iconst,
|
||||
t_make_fconst,
|
||||
t_make_strconst,
|
||||
|
||||
t_free_stack
|
||||
};
|
||||
|
||||
char *names[] = {
|
||||
"heap_hashmap",
|
||||
"hashmap_insert_get",
|
||||
"hashmap_remove",
|
||||
"free_hashmap",
|
||||
"alloc_init",
|
||||
"flisp_alloc",
|
||||
"flisp_realloc",
|
||||
"alloc_clean",
|
||||
"get_type",
|
||||
"make_stack",
|
||||
"make_iconst",
|
||||
"make_fconst",
|
||||
"make_strconst",
|
||||
|
||||
"free_stack"
|
||||
};
|
||||
|
||||
void do_tests(){
|
||||
i32 tlen = sizeof(tests)/sizeof(void*);
|
||||
assert(tlen == sizeof(names)/sizeof(void*)); // If forgot to name a test
|
||||
for(int i = 0; i < tlen; i++){
|
||||
if(tests[i]()){
|
||||
printf("\x1B[31m[FAILED]\x1B[0m test \"%s\"\n", names[i]);
|
||||
exit(1);
|
||||
}
|
||||
else{
|
||||
printf("\x1B[32m[PASSED]\x1B[0m test \"%s\"\n", names[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
#include "config.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
void do_tests();
|
23
src/types.h
23
src/types.h
|
@ -1,22 +1,3 @@
|
|||
/*
|
||||
* The fLisp parser and interpreter
|
||||
* Copyright (C) 2025 Fcalva
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma once
|
||||
|
@ -38,8 +19,6 @@ typedef unsigned int uint;
|
|||
#define PACKED __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
#define NOPOS __attribute__((designated_init))
|
||||
|
||||
enum ValTypes {
|
||||
T_null = 0,
|
||||
T_int = 1,
|
||||
|
@ -47,6 +26,6 @@ enum ValTypes {
|
|||
T_float = 3,
|
||||
T_str = 4,
|
||||
T_fn = 5,
|
||||
T_any = 6
|
||||
T_any = 6 //Used internally for functions taking any type
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue