Add syntax parser and integrate lexical analysis
This commit is contained in:
1 parent
0c47cb3792
commit
35dd18308e
18 files changed
+766
-29
No files matched your search
@@ -1 +1,3 @@
|
|||||||
.priv/
|
.priv/
|
||||||
|
build/
|
||||||
|
programa.bl
|
||||||
+2
-1
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
project(BLCeti VERSION 0.1.0 LANGUAGES C)
|
project(BLCeti VERSION 0.1.0 LANGUAGES C)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 17)
|
set(CMAKE_C_STANDARD 17)
|
||||||
@@ -9,6 +9,7 @@ set(CMAKE_C_EXTENSIONS OFF)
|
|||||||
add_executable(BL
|
add_executable(BL
|
||||||
src/main.c
|
src/main.c
|
||||||
src/lexer.c
|
src/lexer.c
|
||||||
|
src/parser.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(BL PRIVATE include)
|
target_include_directories(BL PRIVATE include)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ set(CMAKE_DEPENDS_LANGUAGES
|
|||||||
set(CMAKE_DEPENDS_DEPENDENCY_FILES
|
set(CMAKE_DEPENDS_DEPENDENCY_FILES
|
||||||
"/home/benicio/Escritorio/BL-Ceti/src/lexer.c" "CMakeFiles/BL.dir/src/lexer.c.o" "gcc" "CMakeFiles/BL.dir/src/lexer.c.o.d"
|
"/home/benicio/Escritorio/BL-Ceti/src/lexer.c" "CMakeFiles/BL.dir/src/lexer.c.o" "gcc" "CMakeFiles/BL.dir/src/lexer.c.o.d"
|
||||||
"/home/benicio/Escritorio/BL-Ceti/src/main.c" "CMakeFiles/BL.dir/src/main.c.o" "gcc" "CMakeFiles/BL.dir/src/main.c.o.d"
|
"/home/benicio/Escritorio/BL-Ceti/src/main.c" "CMakeFiles/BL.dir/src/main.c.o" "gcc" "CMakeFiles/BL.dir/src/main.c.o.d"
|
||||||
|
"/home/benicio/Escritorio/BL-Ceti/src/parser.c" "CMakeFiles/BL.dir/src/parser.c.o" "gcc" "CMakeFiles/BL.dir/src/parser.c.o.d"
|
||||||
"" "BL" "gcc" "CMakeFiles/BL.dir/link.d"
|
"" "BL" "gcc" "CMakeFiles/BL.dir/link.d"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -100,20 +100,36 @@ CMakeFiles/BL.dir/src/lexer.c.s: cmake_force
|
|||||||
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/BL.dir/src/lexer.c.s"
|
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/BL.dir/src/lexer.c.s"
|
||||||
/usr/bin/cc $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/benicio/Escritorio/BL-Ceti/src/lexer.c -o CMakeFiles/BL.dir/src/lexer.c.s
|
/usr/bin/cc $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/benicio/Escritorio/BL-Ceti/src/lexer.c -o CMakeFiles/BL.dir/src/lexer.c.s
|
||||||
|
|
||||||
|
CMakeFiles/BL.dir/src/parser.c.o: CMakeFiles/BL.dir/flags.make
|
||||||
|
CMakeFiles/BL.dir/src/parser.c.o: /home/benicio/Escritorio/BL-Ceti/src/parser.c
|
||||||
|
CMakeFiles/BL.dir/src/parser.c.o: CMakeFiles/BL.dir/compiler_depend.ts
|
||||||
|
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --progress-dir=/home/benicio/Escritorio/BL-Ceti/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Building C object CMakeFiles/BL.dir/src/parser.c.o"
|
||||||
|
/usr/bin/cc $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -MD -MT CMakeFiles/BL.dir/src/parser.c.o -MF CMakeFiles/BL.dir/src/parser.c.o.d -o CMakeFiles/BL.dir/src/parser.c.o -c /home/benicio/Escritorio/BL-Ceti/src/parser.c
|
||||||
|
|
||||||
|
CMakeFiles/BL.dir/src/parser.c.i: cmake_force
|
||||||
|
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Preprocessing C source to CMakeFiles/BL.dir/src/parser.c.i"
|
||||||
|
/usr/bin/cc $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/benicio/Escritorio/BL-Ceti/src/parser.c > CMakeFiles/BL.dir/src/parser.c.i
|
||||||
|
|
||||||
|
CMakeFiles/BL.dir/src/parser.c.s: cmake_force
|
||||||
|
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green "Compiling C source to assembly CMakeFiles/BL.dir/src/parser.c.s"
|
||||||
|
/usr/bin/cc $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/benicio/Escritorio/BL-Ceti/src/parser.c -o CMakeFiles/BL.dir/src/parser.c.s
|
||||||
|
|
||||||
# Object files for target BL
|
# Object files for target BL
|
||||||
BL_OBJECTS = \
|
BL_OBJECTS = \
|
||||||
"CMakeFiles/BL.dir/src/main.c.o" \
|
"CMakeFiles/BL.dir/src/main.c.o" \
|
||||||
"CMakeFiles/BL.dir/src/lexer.c.o"
|
"CMakeFiles/BL.dir/src/lexer.c.o" \
|
||||||
|
"CMakeFiles/BL.dir/src/parser.c.o"
|
||||||
|
|
||||||
# External object files for target BL
|
# External object files for target BL
|
||||||
BL_EXTERNAL_OBJECTS =
|
BL_EXTERNAL_OBJECTS =
|
||||||
|
|
||||||
BL: CMakeFiles/BL.dir/src/main.c.o
|
BL: CMakeFiles/BL.dir/src/main.c.o
|
||||||
BL: CMakeFiles/BL.dir/src/lexer.c.o
|
BL: CMakeFiles/BL.dir/src/lexer.c.o
|
||||||
|
BL: CMakeFiles/BL.dir/src/parser.c.o
|
||||||
BL: CMakeFiles/BL.dir/build.make
|
BL: CMakeFiles/BL.dir/build.make
|
||||||
BL: CMakeFiles/BL.dir/compiler_depend.ts
|
BL: CMakeFiles/BL.dir/compiler_depend.ts
|
||||||
BL: CMakeFiles/BL.dir/link.txt
|
BL: CMakeFiles/BL.dir/link.txt
|
||||||
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --bold --progress-dir=/home/benicio/Escritorio/BL-Ceti/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Linking C executable BL"
|
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --green --bold --progress-dir=/home/benicio/Escritorio/BL-Ceti/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_4) "Linking C executable BL"
|
||||||
$(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/BL.dir/link.txt --verbose=$(VERBOSE)
|
$(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/BL.dir/link.txt --verbose=$(VERBOSE)
|
||||||
|
|
||||||
# Rule to build all files generated by this target.
|
# Rule to build all files generated by this target.
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ file(REMOVE_RECURSE
|
|||||||
"CMakeFiles/BL.dir/src/lexer.c.o.d"
|
"CMakeFiles/BL.dir/src/lexer.c.o.d"
|
||||||
"CMakeFiles/BL.dir/src/main.c.o"
|
"CMakeFiles/BL.dir/src/main.c.o"
|
||||||
"CMakeFiles/BL.dir/src/main.c.o.d"
|
"CMakeFiles/BL.dir/src/main.c.o.d"
|
||||||
|
"CMakeFiles/BL.dir/src/parser.c.o"
|
||||||
|
"CMakeFiles/BL.dir/src/parser.c.o.d"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Per-language clean rules from dependency scanning.
|
# Per-language clean rules from dependency scanning.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ BL: \
|
|||||||
/usr/lib/gcc/x86_64-pc-linux-gnu/16/crtbeginS.o \
|
/usr/lib/gcc/x86_64-pc-linux-gnu/16/crtbeginS.o \
|
||||||
CMakeFiles/BL.dir/src/main.c.o \
|
CMakeFiles/BL.dir/src/main.c.o \
|
||||||
CMakeFiles/BL.dir/src/lexer.c.o \
|
CMakeFiles/BL.dir/src/lexer.c.o \
|
||||||
|
CMakeFiles/BL.dir/src/parser.c.o \
|
||||||
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc.a \
|
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc.a \
|
||||||
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc_s_asneeded.so \
|
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc_s_asneeded.so \
|
||||||
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc_s_asneeded.so \
|
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc_s_asneeded.so \
|
||||||
@@ -46,6 +47,8 @@ CMakeFiles/BL.dir/src/main.c.o:
|
|||||||
|
|
||||||
CMakeFiles/BL.dir/src/lexer.c.o:
|
CMakeFiles/BL.dir/src/lexer.c.o:
|
||||||
|
|
||||||
|
CMakeFiles/BL.dir/src/parser.c.o:
|
||||||
|
|
||||||
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc.a:
|
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc.a:
|
||||||
|
|
||||||
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc_s_asneeded.so:
|
/usr/lib/gcc/x86_64-pc-linux-gnu/16/libgcc_s_asneeded.so:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/usr/bin/cc -Wl,--dependency-file=CMakeFiles/BL.dir/link.d CMakeFiles/BL.dir/src/main.c.o CMakeFiles/BL.dir/src/lexer.c.o -o BL
|
/usr/bin/cc -Wl,--dependency-file=CMakeFiles/BL.dir/link.d CMakeFiles/BL.dir/src/main.c.o CMakeFiles/BL.dir/src/lexer.c.o CMakeFiles/BL.dir/src/parser.c.o -o BL
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
CMAKE_PROGRESS_1 = 1
|
CMAKE_PROGRESS_1 = 1
|
||||||
CMAKE_PROGRESS_2 = 2
|
CMAKE_PROGRESS_2 = 2
|
||||||
CMAKE_PROGRESS_3 = 3
|
CMAKE_PROGRESS_3 = 3
|
||||||
|
CMAKE_PROGRESS_4 = 4
|
||||||
|
|
||||||
Binary file not shown.
@@ -3,11 +3,13 @@ CMakeFiles/BL.dir/src/main.c.o: \
|
|||||||
/home/benicio/Escritorio/BL-Ceti/include/lexer.h \
|
/home/benicio/Escritorio/BL-Ceti/include/lexer.h \
|
||||||
/usr/lib/gcc/x86_64-pc-linux-gnu/16/include/stdbool.h \
|
/usr/lib/gcc/x86_64-pc-linux-gnu/16/include/stdbool.h \
|
||||||
/usr/lib/gcc/x86_64-pc-linux-gnu/16/include/stddef.h \
|
/usr/lib/gcc/x86_64-pc-linux-gnu/16/include/stddef.h \
|
||||||
/usr/include/stdio.h /usr/include/bits/libc-header-start.h \
|
/home/benicio/Escritorio/BL-Ceti/include/parser.h \
|
||||||
/usr/include/features.h /usr/include/features-time64.h \
|
/home/benicio/Escritorio/BL-Ceti/include/lexer.h /usr/include/stdio.h \
|
||||||
/usr/include/bits/wordsize.h /usr/include/bits/timesize.h \
|
/usr/include/bits/libc-header-start.h /usr/include/features.h \
|
||||||
/usr/include/sys/cdefs.h /usr/include/bits/long-double.h \
|
/usr/include/features-time64.h /usr/include/bits/wordsize.h \
|
||||||
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
|
/usr/include/bits/timesize.h /usr/include/sys/cdefs.h \
|
||||||
|
/usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
|
||||||
|
/usr/include/gnu/stubs-64.h \
|
||||||
/usr/lib/gcc/x86_64-pc-linux-gnu/16/include/stdarg.h \
|
/usr/lib/gcc/x86_64-pc-linux-gnu/16/include/stdarg.h \
|
||||||
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
|
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
|
||||||
/usr/include/bits/time64.h /usr/include/bits/types/__fpos_t.h \
|
/usr/include/bits/time64.h /usr/include/bits/types/__fpos_t.h \
|
||||||
|
|||||||
@@ -85,12 +85,12 @@ clean: CMakeFiles/BL.dir/clean
|
|||||||
CMakeFiles/BL.dir/all:
|
CMakeFiles/BL.dir/all:
|
||||||
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/depend
|
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/depend
|
||||||
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/build
|
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/build
|
||||||
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --progress-dir=/home/benicio/Escritorio/BL-Ceti/build/CMakeFiles --progress-num=1,2,3 "Built target BL"
|
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --progress-dir=/home/benicio/Escritorio/BL-Ceti/build/CMakeFiles --progress-num=1,2,3,4 "Built target BL"
|
||||||
.PHONY : CMakeFiles/BL.dir/all
|
.PHONY : CMakeFiles/BL.dir/all
|
||||||
|
|
||||||
# Build rule for subdir invocation for target.
|
# Build rule for subdir invocation for target.
|
||||||
CMakeFiles/BL.dir/rule: cmake_check_build_system
|
CMakeFiles/BL.dir/rule: cmake_check_build_system
|
||||||
$(CMAKE_COMMAND) -E cmake_progress_start /home/benicio/Escritorio/BL-Ceti/build/CMakeFiles 3
|
$(CMAKE_COMMAND) -E cmake_progress_start /home/benicio/Escritorio/BL-Ceti/build/CMakeFiles 4
|
||||||
$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 CMakeFiles/BL.dir/all
|
$(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 CMakeFiles/BL.dir/all
|
||||||
$(CMAKE_COMMAND) -E cmake_progress_start /home/benicio/Escritorio/BL-Ceti/build/CMakeFiles 0
|
$(CMAKE_COMMAND) -E cmake_progress_start /home/benicio/Escritorio/BL-Ceti/build/CMakeFiles 0
|
||||||
.PHONY : CMakeFiles/BL.dir/rule
|
.PHONY : CMakeFiles/BL.dir/rule
|
||||||
@@ -102,7 +102,7 @@ BL: CMakeFiles/BL.dir/rule
|
|||||||
# codegen rule for target.
|
# codegen rule for target.
|
||||||
CMakeFiles/BL.dir/codegen:
|
CMakeFiles/BL.dir/codegen:
|
||||||
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/codegen
|
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/codegen
|
||||||
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --progress-dir=/home/benicio/Escritorio/BL-Ceti/build/CMakeFiles --progress-num=1,2,3 "Finished codegen for target BL"
|
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --progress-dir=/home/benicio/Escritorio/BL-Ceti/build/CMakeFiles --progress-num=1,2,3,4 "Finished codegen for target BL"
|
||||||
.PHONY : CMakeFiles/BL.dir/codegen
|
.PHONY : CMakeFiles/BL.dir/codegen
|
||||||
|
|
||||||
# clean rule for target.
|
# clean rule for target.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
3
|
4
|
||||||
@@ -222,6 +222,30 @@ src/main.c.s:
|
|||||||
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/src/main.c.s
|
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/src/main.c.s
|
||||||
.PHONY : src/main.c.s
|
.PHONY : src/main.c.s
|
||||||
|
|
||||||
|
src/parser.o: src/parser.c.o
|
||||||
|
.PHONY : src/parser.o
|
||||||
|
|
||||||
|
# target to build an object file
|
||||||
|
src/parser.c.o:
|
||||||
|
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/src/parser.c.o
|
||||||
|
.PHONY : src/parser.c.o
|
||||||
|
|
||||||
|
src/parser.i: src/parser.c.i
|
||||||
|
.PHONY : src/parser.i
|
||||||
|
|
||||||
|
# target to preprocess a source file
|
||||||
|
src/parser.c.i:
|
||||||
|
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/src/parser.c.i
|
||||||
|
.PHONY : src/parser.c.i
|
||||||
|
|
||||||
|
src/parser.s: src/parser.c.s
|
||||||
|
.PHONY : src/parser.s
|
||||||
|
|
||||||
|
# target to generate assembly for a file
|
||||||
|
src/parser.c.s:
|
||||||
|
$(MAKE) $(MAKESILENT) -f CMakeFiles/BL.dir/build.make CMakeFiles/BL.dir/src/parser.c.s
|
||||||
|
.PHONY : src/parser.c.s
|
||||||
|
|
||||||
# Help Target
|
# Help Target
|
||||||
help:
|
help:
|
||||||
@echo "The following are some of the valid targets for this Makefile:"
|
@echo "The following are some of the valid targets for this Makefile:"
|
||||||
@@ -241,6 +265,9 @@ help:
|
|||||||
@echo "... src/main.o"
|
@echo "... src/main.o"
|
||||||
@echo "... src/main.i"
|
@echo "... src/main.i"
|
||||||
@echo "... src/main.s"
|
@echo "... src/main.s"
|
||||||
|
@echo "... src/parser.o"
|
||||||
|
@echo "... src/parser.i"
|
||||||
|
@echo "... src/parser.s"
|
||||||
.PHONY : help
|
.PHONY : help
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef BL_CETI_PARSER_H
|
||||||
|
#define BL_CETI_PARSER_H
|
||||||
|
|
||||||
|
#include "lexer.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char code[6];
|
||||||
|
char message[160];
|
||||||
|
size_t line;
|
||||||
|
size_t column;
|
||||||
|
} BlParseError;
|
||||||
|
|
||||||
|
bool bl_parse(const BlToken *tokens, size_t count, BlParseError *error);
|
||||||
|
|
||||||
|
#endif
|
||||||
+5
-2
@@ -1,4 +1,7 @@
|
|||||||
|
cat > /tmp/bl-error.bl <<'EOF'
|
||||||
fn main() {
|
fn main() {
|
||||||
let mensaje: String = "Hola desde BL-Ceti";
|
let numero: Int = ;
|
||||||
print(mensaje);
|
|
||||||
}
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
./build/BL .C /tmp/bl-error.bl
|
||||||
+36
-14
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -16,6 +16,7 @@ static char *read_file(const char *path, size_t *length)
|
|||||||
|
|
||||||
if (fseek(file, 0, SEEK_END) != 0) {
|
if (fseek(file, 0, SEEK_END) != 0) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
fprintf(stderr, "BL: no se pudo leer el archivo.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ static char *read_file(const char *path, size_t *length)
|
|||||||
|
|
||||||
if (size < 0 || fseek(file, 0, SEEK_SET) != 0) {
|
if (size < 0 || fseek(file, 0, SEEK_SET) != 0) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
fprintf(stderr, "BL: no se pudo determinar el tamaño del archivo.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +48,7 @@ static char *read_file(const char *path, size_t *length)
|
|||||||
buffer[read_count] = '\0';
|
buffer[read_count] = '\0';
|
||||||
*length = read_count;
|
*length = read_count;
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,29 +57,48 @@ static int analyze_file(const char *path)
|
|||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
char *source = read_file(path, &length);
|
char *source = read_file(path, &length);
|
||||||
|
|
||||||
if (source == NULL) return 1;
|
if (source == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
BlLexResult result = {0};
|
BlLexResult lex_result = {0};
|
||||||
bool success = bl_lex(source, length, &result);
|
|
||||||
|
|
||||||
if (!success) {
|
if (!bl_lex(source, length, &lex_result)) {
|
||||||
fprintf(stderr, "%s:%zu:%zu: error %s: %s\n",
|
fprintf(stderr, "%s:%zu:%zu: error %s: %s\n",
|
||||||
path,
|
path,
|
||||||
result.error.line,
|
lex_result.error.line,
|
||||||
result.error.column,
|
lex_result.error.column,
|
||||||
result.error.code,
|
lex_result.error.code,
|
||||||
result.error.message);
|
lex_result.error.message);
|
||||||
bl_lex_result_destroy(&result);
|
|
||||||
|
bl_lex_result_destroy(&lex_result);
|
||||||
free(source);
|
free(source);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("BL-Ceti: analisis lexico correcto: %s\n", path);
|
BlParseError parse_error = {0};
|
||||||
printf("Tokens reconocidos: %zu\n",
|
|
||||||
result.count > 0 ? result.count - 1 : 0);
|
|
||||||
|
|
||||||
bl_lex_result_destroy(&result);
|
if (!bl_parse(lex_result.tokens, lex_result.count, &parse_error)) {
|
||||||
|
fprintf(stderr, "%s:%zu:%zu: error %s: %s\n",
|
||||||
|
path,
|
||||||
|
parse_error.line,
|
||||||
|
parse_error.column,
|
||||||
|
parse_error.code,
|
||||||
|
parse_error.message);
|
||||||
|
|
||||||
|
bl_lex_result_destroy(&lex_result);
|
||||||
|
free(source);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("BL-Ceti 0.1.0: analisis correcto: %s\n", path);
|
||||||
|
printf("Tokens reconocidos: %zu\n",
|
||||||
|
lex_result.count > 0 ? lex_result.count - 1 : 0);
|
||||||
|
printf("Sintaxis: correcta\n");
|
||||||
|
|
||||||
|
bl_lex_result_destroy(&lex_result);
|
||||||
free(source);
|
free(source);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+639
@@ -0,0 +1,639 @@
|
|||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const BlToken *tokens;
|
||||||
|
size_t count;
|
||||||
|
size_t position;
|
||||||
|
BlParseError *error;
|
||||||
|
bool failed;
|
||||||
|
} Parser;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool identifier;
|
||||||
|
bool call;
|
||||||
|
} ExprInfo;
|
||||||
|
|
||||||
|
static const BlToken *current(Parser *parser)
|
||||||
|
{
|
||||||
|
if (parser->position >= parser->count) {
|
||||||
|
return &parser->tokens[parser->count - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return &parser->tokens[parser->position];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool check(Parser *parser, BlTokenType type)
|
||||||
|
{
|
||||||
|
return current(parser)->type == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const BlToken *advance(Parser *parser)
|
||||||
|
{
|
||||||
|
const BlToken *token = current(parser);
|
||||||
|
|
||||||
|
if (token->type != BL_EOF) {
|
||||||
|
parser->position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fail_at(Parser *parser, const BlToken *token,
|
||||||
|
const char *code, const char *message)
|
||||||
|
{
|
||||||
|
if (!parser->failed) {
|
||||||
|
parser->failed = true;
|
||||||
|
|
||||||
|
snprintf(parser->error->code, sizeof parser->error->code,
|
||||||
|
"%s", code);
|
||||||
|
snprintf(parser->error->message, sizeof parser->error->message,
|
||||||
|
"%s", message);
|
||||||
|
|
||||||
|
parser->error->line = token->line;
|
||||||
|
parser->error->column = token->column;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool expect(Parser *parser, BlTokenType type,
|
||||||
|
const char *message)
|
||||||
|
{
|
||||||
|
if (check(parser, type)) {
|
||||||
|
advance(parser);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fail_at(parser, current(parser), "E1001", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_expression(Parser *parser, ExprInfo *info);
|
||||||
|
static bool parse_statement(Parser *parser);
|
||||||
|
static bool parse_block(Parser *parser);
|
||||||
|
|
||||||
|
static bool parse_type(Parser *parser, bool allow_void)
|
||||||
|
{
|
||||||
|
BlTokenType type = current(parser)->type;
|
||||||
|
|
||||||
|
if (type == BL_INT_TYPE ||
|
||||||
|
type == BL_FLOAT_TYPE ||
|
||||||
|
type == BL_BOOL_TYPE ||
|
||||||
|
type == BL_STRING_TYPE) {
|
||||||
|
advance(parser);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allow_void && type == BL_VOID_TYPE) {
|
||||||
|
advance(parser);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fail_at(parser, current(parser), "E1001",
|
||||||
|
"Se esperaba un tipo valido.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_primary(Parser *parser, ExprInfo *info)
|
||||||
|
{
|
||||||
|
const BlToken *token = current(parser);
|
||||||
|
|
||||||
|
info->identifier = false;
|
||||||
|
info->call = false;
|
||||||
|
|
||||||
|
switch (token->type) {
|
||||||
|
case BL_INTEGER:
|
||||||
|
case BL_FLOAT:
|
||||||
|
case BL_STRING:
|
||||||
|
case BL_TRUE:
|
||||||
|
case BL_FALSE:
|
||||||
|
advance(parser);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case BL_IDENTIFIER:
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
if (check(parser, BL_LPAREN)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
if (!check(parser, BL_RPAREN)) {
|
||||||
|
ExprInfo argument;
|
||||||
|
|
||||||
|
if (!parse_expression(parser, &argument)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (check(parser, BL_COMMA)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
if (check(parser, BL_RPAREN)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_expression(parser, &argument)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expect(parser, BL_RPAREN,
|
||||||
|
"Se esperaba ')' al cerrar la llamada.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->call = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->identifier = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case BL_LPAREN: {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
ExprInfo inner;
|
||||||
|
|
||||||
|
if (!parse_expression(parser, &inner)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expect(parser, BL_RPAREN,
|
||||||
|
"Se esperaba ')' en la expresion.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fail_at(parser, token, "E1001",
|
||||||
|
"Se esperaba una expresion.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_unary(Parser *parser, ExprInfo *info)
|
||||||
|
{
|
||||||
|
if (check(parser, BL_MINUS) || check(parser, BL_NOT)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
if (!parse_unary(parser, info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->identifier = false;
|
||||||
|
info->call = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_primary(parser, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_cast(Parser *parser, ExprInfo *info)
|
||||||
|
{
|
||||||
|
if (!parse_unary(parser, info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (check(parser, BL_AS)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
if (!parse_type(parser, false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->identifier = false;
|
||||||
|
info->call = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_multiplication(Parser *parser, ExprInfo *info)
|
||||||
|
{
|
||||||
|
if (!parse_cast(parser, info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (check(parser, BL_STAR) ||
|
||||||
|
check(parser, BL_SLASH) ||
|
||||||
|
check(parser, BL_PERCENT)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
ExprInfo right;
|
||||||
|
|
||||||
|
if (!parse_cast(parser, &right)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->identifier = false;
|
||||||
|
info->call = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_addition(Parser *parser, ExprInfo *info)
|
||||||
|
{
|
||||||
|
if (!parse_multiplication(parser, info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (check(parser, BL_PLUS) || check(parser, BL_MINUS)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
ExprInfo right;
|
||||||
|
|
||||||
|
if (!parse_multiplication(parser, &right)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->identifier = false;
|
||||||
|
info->call = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_relational(BlTokenType type)
|
||||||
|
{
|
||||||
|
return type == BL_LESS ||
|
||||||
|
type == BL_LESS_EQUAL ||
|
||||||
|
type == BL_GREATER ||
|
||||||
|
type == BL_GREATER_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_relation(Parser *parser, ExprInfo *info)
|
||||||
|
{
|
||||||
|
if (!parse_addition(parser, info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_relational(current(parser)->type)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
ExprInfo right;
|
||||||
|
|
||||||
|
if (!parse_addition(parser, &right)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->identifier = false;
|
||||||
|
info->call = false;
|
||||||
|
|
||||||
|
if (is_relational(current(parser)->type)) {
|
||||||
|
return fail_at(parser, current(parser), "E1005",
|
||||||
|
"Las comparaciones relacionales no se pueden encadenar.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_equality(Parser *parser, ExprInfo *info)
|
||||||
|
{
|
||||||
|
if (!parse_relation(parser, info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check(parser, BL_EQUAL) || check(parser, BL_NOT_EQUAL)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
ExprInfo right;
|
||||||
|
|
||||||
|
if (!parse_relation(parser, &right)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->identifier = false;
|
||||||
|
info->call = false;
|
||||||
|
|
||||||
|
if (check(parser, BL_EQUAL) || check(parser, BL_NOT_EQUAL)) {
|
||||||
|
return fail_at(parser, current(parser), "E1005",
|
||||||
|
"Las comparaciones de igualdad no se pueden encadenar.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_and(Parser *parser, ExprInfo *info)
|
||||||
|
{
|
||||||
|
if (!parse_equality(parser, info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (check(parser, BL_AND)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
ExprInfo right;
|
||||||
|
|
||||||
|
if (!parse_equality(parser, &right)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->identifier = false;
|
||||||
|
info->call = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_expression(Parser *parser, ExprInfo *info)
|
||||||
|
{
|
||||||
|
if (!parse_and(parser, info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (check(parser, BL_OR)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
ExprInfo right;
|
||||||
|
|
||||||
|
if (!parse_and(parser, &right)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->identifier = false;
|
||||||
|
info->call = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_assignment_operator(BlTokenType type)
|
||||||
|
{
|
||||||
|
return type == BL_ASSIGN ||
|
||||||
|
type == BL_PLUS_ASSIGN ||
|
||||||
|
type == BL_MINUS_ASSIGN ||
|
||||||
|
type == BL_STAR_ASSIGN ||
|
||||||
|
type == BL_SLASH_ASSIGN ||
|
||||||
|
type == BL_PERCENT_ASSIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_variable(Parser *parser)
|
||||||
|
{
|
||||||
|
advance(parser); /* let o var */
|
||||||
|
|
||||||
|
if (!expect(parser, BL_IDENTIFIER,
|
||||||
|
"Se esperaba un nombre de variable.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check(parser, BL_COLON)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
if (!parse_type(parser, false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expect(parser, BL_ASSIGN,
|
||||||
|
"Se esperaba '=' para inicializar la variable.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprInfo value;
|
||||||
|
|
||||||
|
if (!parse_expression(parser, &value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expect(parser, BL_SEMICOLON,
|
||||||
|
"Se esperaba ';' al final de la declaracion.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_if(Parser *parser)
|
||||||
|
{
|
||||||
|
advance(parser); /* if */
|
||||||
|
|
||||||
|
ExprInfo condition;
|
||||||
|
|
||||||
|
if (!parse_expression(parser, &condition)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_block(parser)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check(parser, BL_ELSE)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
if (check(parser, BL_IF)) {
|
||||||
|
return parse_if(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_block(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_while(Parser *parser)
|
||||||
|
{
|
||||||
|
advance(parser); /* while */
|
||||||
|
|
||||||
|
ExprInfo condition;
|
||||||
|
|
||||||
|
if (!parse_expression(parser, &condition)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_block(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_return(Parser *parser)
|
||||||
|
{
|
||||||
|
advance(parser); /* return */
|
||||||
|
|
||||||
|
if (!check(parser, BL_SEMICOLON)) {
|
||||||
|
ExprInfo value;
|
||||||
|
|
||||||
|
if (!parse_expression(parser, &value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expect(parser, BL_SEMICOLON,
|
||||||
|
"Se esperaba ';' despues de return.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_simple_statement(Parser *parser)
|
||||||
|
{
|
||||||
|
ExprInfo expression;
|
||||||
|
|
||||||
|
if (!parse_expression(parser, &expression)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_assignment_operator(current(parser)->type)) {
|
||||||
|
if (!expression.identifier) {
|
||||||
|
return fail_at(parser, current(parser), "E1006",
|
||||||
|
"El lado izquierdo de una asignacion debe ser una variable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
ExprInfo value;
|
||||||
|
|
||||||
|
if (!parse_expression(parser, &value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!expression.call) {
|
||||||
|
return fail_at(parser, current(parser), "E1007",
|
||||||
|
"Una sentencia de expresion debe ser una llamada a funcion.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return expect(parser, BL_SEMICOLON,
|
||||||
|
"Se esperaba ';' al final de la sentencia.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_statement(Parser *parser)
|
||||||
|
{
|
||||||
|
switch (current(parser)->type) {
|
||||||
|
case BL_LET:
|
||||||
|
case BL_VAR:
|
||||||
|
return parse_variable(parser);
|
||||||
|
|
||||||
|
case BL_IF:
|
||||||
|
return parse_if(parser);
|
||||||
|
|
||||||
|
case BL_WHILE:
|
||||||
|
return parse_while(parser);
|
||||||
|
|
||||||
|
case BL_BREAK:
|
||||||
|
case BL_CONTINUE:
|
||||||
|
advance(parser);
|
||||||
|
return expect(parser, BL_SEMICOLON,
|
||||||
|
"Se esperaba ';' despues de la sentencia.");
|
||||||
|
|
||||||
|
case BL_RETURN:
|
||||||
|
return parse_return(parser);
|
||||||
|
|
||||||
|
case BL_LBRACE:
|
||||||
|
return parse_block(parser);
|
||||||
|
|
||||||
|
case BL_IDENTIFIER:
|
||||||
|
case BL_INTEGER:
|
||||||
|
case BL_FLOAT:
|
||||||
|
case BL_STRING:
|
||||||
|
case BL_TRUE:
|
||||||
|
case BL_FALSE:
|
||||||
|
case BL_LPAREN:
|
||||||
|
case BL_MINUS:
|
||||||
|
case BL_NOT:
|
||||||
|
return parse_simple_statement(parser);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fail_at(parser, current(parser), "E1001",
|
||||||
|
"Sentencia no valida.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_block(Parser *parser)
|
||||||
|
{
|
||||||
|
if (!expect(parser, BL_LBRACE,
|
||||||
|
"Se esperaba '{' para comenzar el bloque.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!check(parser, BL_RBRACE) &&
|
||||||
|
!check(parser, BL_EOF) &&
|
||||||
|
!parser->failed) {
|
||||||
|
if (!parse_statement(parser)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expect(parser, BL_RBRACE,
|
||||||
|
"Se esperaba '}' para cerrar el bloque.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_function(Parser *parser)
|
||||||
|
{
|
||||||
|
advance(parser); /* fn */
|
||||||
|
|
||||||
|
if (!expect(parser, BL_IDENTIFIER,
|
||||||
|
"Se esperaba el nombre de la funcion.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expect(parser, BL_LPAREN,
|
||||||
|
"Se esperaba '(' despues del nombre de la funcion.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check(parser, BL_RPAREN)) {
|
||||||
|
for (;;) {
|
||||||
|
if (!expect(parser, BL_IDENTIFIER,
|
||||||
|
"Se esperaba el nombre del parametro.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expect(parser, BL_COLON,
|
||||||
|
"Se esperaba ':' despues del nombre del parametro.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_type(parser, false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check(parser, BL_COMMA)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
if (check(parser, BL_RPAREN)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expect(parser, BL_RPAREN,
|
||||||
|
"Se esperaba ')' despues de los parametros.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check(parser, BL_ARROW)) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
if (!parse_type(parser, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_block(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bl_parse(const BlToken *tokens, size_t count, BlParseError *error)
|
||||||
|
{
|
||||||
|
if (tokens == NULL || count == 0 || error == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(error, 0, sizeof *error);
|
||||||
|
|
||||||
|
Parser parser = {
|
||||||
|
.tokens = tokens,
|
||||||
|
.count = count,
|
||||||
|
.position = 0,
|
||||||
|
.error = error,
|
||||||
|
.failed = false
|
||||||
|
};
|
||||||
|
|
||||||
|
while (!check(&parser, BL_EOF) && !parser.failed) {
|
||||||
|
if (!check(&parser, BL_FN)) {
|
||||||
|
return fail_at(&parser, current(&parser), "E1001",
|
||||||
|
"En el nivel superior solo se permiten funciones.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_function(&parser)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !parser.failed && check(&parser, BL_EOF);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user