toolchain: add a program for compiling ipc interface definitions
ifc can be used to compile .if files into self-contained header-only C libraries, which can be used to send/receive messages that conform to the described interface.
This commit is contained in:
@@ -10,7 +10,7 @@ fi
|
|||||||
|
|
||||||
build_type=Debug
|
build_type=Debug
|
||||||
source_dir=$(realpath $(dirname "$0"))
|
source_dir=$(realpath $(dirname "$0"))
|
||||||
native_build_dir=$source_dir/build-native
|
toolchain_build_dir=$source_dir/build/toolchain
|
||||||
target_build_dir=$source_dir/build
|
target_build_dir=$source_dir/build
|
||||||
sysroot_dir=$target_build_dir/sysroot
|
sysroot_dir=$target_build_dir/sysroot
|
||||||
|
|
||||||
@@ -19,25 +19,35 @@ if [ ! -d "$source_dir/arch/$target_arch" ]; then
|
|||||||
exit -1
|
exit -1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf $native_build_dir $target_build_dir
|
rm -rf $toolchain_build_dir $target_build_dir
|
||||||
mkdir -p $native_build_dir $target_build_dir
|
mkdir -p $toolchain_build_dir $target_build_dir
|
||||||
|
|
||||||
pushd $native_build_dir > /dev/null
|
pushd $toolchain_build_dir > /dev/null
|
||||||
|
|
||||||
cmake \
|
cmake \
|
||||||
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY="$native_build_dir/bin" \
|
|
||||||
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$native_build_dir/lib" \
|
|
||||||
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$native_build_dir/lib" \
|
|
||||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||||
-DCMAKE_BUILD_TYPE=$build_type \
|
-DCMAKE_BUILD_TYPE=$build_type \
|
||||||
$source_dir/kernel/tools
|
$source_dir/toolchain
|
||||||
|
|
||||||
|
case $CMAKE_GENERATOR in
|
||||||
|
Ninja)
|
||||||
|
ninja
|
||||||
|
;;
|
||||||
|
"Unix Makefiles")
|
||||||
|
make
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
make
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
|
||||||
pushd $target_build_dir > /dev/null
|
pushd $target_build_dir > /dev/null
|
||||||
|
|
||||||
cmake \
|
cmake \
|
||||||
-DBUILD_TOOLS_DIR=$native_build_dir/bin \
|
-DBUILD_TOOLS_DIR=$toolchain_build_dir/bin \
|
||||||
-DCMAKE_INSTALL_PREFIX=$sysroot_dir \
|
-DCMAKE_INSTALL_PREFIX=$sysroot_dir \
|
||||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||||
-DTARGET_ARCH=$target_arch \
|
-DTARGET_ARCH=$target_arch \
|
||||||
|
|||||||
17
toolchain/CMakeLists.txt
Normal file
17
toolchain/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
project(rosetta-toolchain C CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||||
|
|
||||||
|
find_package(Bluelib REQUIRED COMPONENTS Core Ds Term Cmd Io)
|
||||||
|
|
||||||
|
add_subdirectory(
|
||||||
|
../kernel/tools
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/kernel-tools)
|
||||||
|
|
||||||
|
add_subdirectory(ifc)
|
||||||
212
toolchain/cmake/FindBluelib.cmake
Normal file
212
toolchain/cmake/FindBluelib.cmake
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
#[=======================================================================[.rst:
|
||||||
|
FindBluelib
|
||||||
|
------------
|
||||||
|
|
||||||
|
Find the Bluelib library and header directories
|
||||||
|
|
||||||
|
Imported Targets
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This module defines the following :prop_tgt:`IMPORTED` target:
|
||||||
|
|
||||||
|
``Bluelib::Bluelib``
|
||||||
|
The Bluelib library, if found
|
||||||
|
|
||||||
|
Result Variables
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This module will set the following variables in your project:
|
||||||
|
|
||||||
|
``Bluelib_FOUND``
|
||||||
|
true if the Bluelib C headers and libraries were found
|
||||||
|
``Bluelib_INCLUDE_DIR``
|
||||||
|
directories containing the Bluelib C headers.
|
||||||
|
|
||||||
|
``Bluelib_LIBRARY``
|
||||||
|
the C library to link against
|
||||||
|
|
||||||
|
Hints
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
The user may set the environment variable ``Bluelib_PREFIX`` to the root
|
||||||
|
directory of a Bluelib library installation.
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
set (Bluelib_SEARCH_PATHS
|
||||||
|
~/Library/Frameworks
|
||||||
|
/Library/Frameworks
|
||||||
|
/usr/local
|
||||||
|
/usr/local/share
|
||||||
|
/usr
|
||||||
|
/sw # Fink
|
||||||
|
/opt/local # DarwinPorts
|
||||||
|
/opt/csw # Blastwave
|
||||||
|
/opt
|
||||||
|
${Bluelib_PREFIX}
|
||||||
|
$ENV{Bluelib_PREFIX})
|
||||||
|
|
||||||
|
if (Bluelib_STATIC)
|
||||||
|
set(_lib_suffix "-s")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set(supported_components
|
||||||
|
Core Ds Term Cmd Io Serial Compress
|
||||||
|
Core-MM)
|
||||||
|
set(components ${Bluelib_FIND_COMPONENTS})
|
||||||
|
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
|
||||||
|
|
||||||
|
if (NOT components)
|
||||||
|
set(components ${supported_components})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set(required_vars)
|
||||||
|
|
||||||
|
foreach (component ${components})
|
||||||
|
if (NOT "${component}" IN_LIST supported_components)
|
||||||
|
message(FATAL_ERROR "'${component}' is not a valid Bluelib module.\nSupported modules: ${supported_components_string_list}")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
string(TOLOWER ${component} header_name)
|
||||||
|
string(REPLACE "-mm" "" header_name "${header_name}")
|
||||||
|
|
||||||
|
string(TOLOWER ${component} lib_name)
|
||||||
|
set(lib_name ${lib_name}${_lib_suffix})
|
||||||
|
|
||||||
|
set(cmake_lib_name ${component})
|
||||||
|
string(REPLACE "-" "_" cmake_lib_name "${cmake_lib_name}")
|
||||||
|
|
||||||
|
if (NOT Bluelib_${cmake_lib_dir}_INCLUDE_DIR)
|
||||||
|
find_path(Bluelib_${cmake_lib_name}_INCLUDE_DIR
|
||||||
|
NAMES blue/${header_name}.h blue/${header_name}.hpp
|
||||||
|
${Bluelib_FIND_ARGS}
|
||||||
|
PATH_SUFFIXES include
|
||||||
|
PATHS ${Bluelib_SEARCH_PATHS})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT Bluelib_${cmake_lib_dir}_LIBRARY)
|
||||||
|
find_library(Bluelib_${cmake_lib_name}_LIBRARY
|
||||||
|
NAMES blue-${lib_name} ${Bluelib_FIND_ARGS}
|
||||||
|
PATH_SUFFIXES lib
|
||||||
|
PATHS ${Bluelib_SEARCH_PATHS})
|
||||||
|
else ()
|
||||||
|
# on Windows, ensure paths are in canonical format (forward slahes):
|
||||||
|
file(TO_CMAKE_PATH "${Bluelib_${cmake_lib_name}_LIBRARY}" Bluelib_${cmake_lib_name}_LIBRARY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND required_vars Bluelib_${cmake_lib_name}_INCLUDE_DIR Bluelib_${cmake_lib_name}_LIBRARY)
|
||||||
|
endforeach (component)
|
||||||
|
|
||||||
|
unset(Bluelib_FIND_ARGS)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(Bluelib
|
||||||
|
REQUIRED_VARS ${required_vars})
|
||||||
|
|
||||||
|
if (Bluelib_FOUND)
|
||||||
|
set(created_targets)
|
||||||
|
foreach (component ${components})
|
||||||
|
string(TOLOWER ${component} header_name)
|
||||||
|
string(REPLACE "-mm" "" header_name "${header_name}")
|
||||||
|
|
||||||
|
string(TOLOWER ${component} lib_name)
|
||||||
|
set(lib_name ${lib_name}${_lib_suffix})
|
||||||
|
|
||||||
|
set(cmake_lib_name ${component})
|
||||||
|
string(REPLACE "-" "_" cmake_lib_name "${cmake_lib_name}")
|
||||||
|
|
||||||
|
if(NOT TARGET Bluelib::${component})
|
||||||
|
add_library(Bluelib::${component} UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(Bluelib::${component} PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${Bluelib_${cmake_lib_name}_INCLUDE_DIR}")
|
||||||
|
target_compile_definitions(Bluelib::${component} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
|
||||||
|
|
||||||
|
if (Bluelib_STATIC)
|
||||||
|
target_compile_definitions(Bluelib::${component} INTERFACE BLUELIB_STATIC=1)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set_target_properties(Bluelib::${component} PROPERTIES
|
||||||
|
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||||
|
IMPORTED_LOCATION "${Bluelib_${cmake_lib_name}_LIBRARY}")
|
||||||
|
set(created_targets ${created_targets} ${component})
|
||||||
|
endif ()
|
||||||
|
endforeach (component)
|
||||||
|
|
||||||
|
foreach (component ${created_targets})
|
||||||
|
if ("${component}" STREQUAL "Ds")
|
||||||
|
if (NOT TARGET Bluelib::Core)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Ds' depends on 'Core', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
target_link_libraries(Bluelib::Ds INTERFACE Bluelib::Core)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if ("${component}" STREQUAL "Term")
|
||||||
|
if (NOT TARGET Bluelib::Core)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Core', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT TARGET Bluelib::Ds)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Ds', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
target_link_libraries(Bluelib::Term INTERFACE Bluelib::Core Bluelib::Ds)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if ("${component}" STREQUAL "Serial")
|
||||||
|
if (NOT TARGET Bluelib::Core)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Serial' depends on 'Core', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT TARGET Bluelib::Ds)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Serial' depends on 'Ds', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
target_link_libraries(Bluelib::Serial INTERFACE Bluelib::Core Bluelib::Ds)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if ("${component}" STREQUAL "Cmd")
|
||||||
|
if (NOT TARGET Bluelib::Core)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Core', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT TARGET Bluelib::Ds)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Ds', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT TARGET Bluelib::Term)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Term', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
target_link_libraries(Bluelib::Cmd INTERFACE Bluelib::Core Bluelib::Ds Bluelib::Term)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if ("${component}" STREQUAL "Io")
|
||||||
|
if (NOT TARGET Bluelib::Core)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Io' depends on 'Core', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT TARGET Bluelib::Ds)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Io' depends on 'Ds', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
target_link_libraries(Bluelib::Io INTERFACE Bluelib::Core Bluelib::Ds)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if ("${component}" STREQUAL "Compress")
|
||||||
|
if (NOT TARGET Bluelib::Core)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Compress' depends on 'Core', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
target_link_libraries(Bluelib::Compress INTERFACE Bluelib::Core Bluelib::Ds)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if ("${component}" STREQUAL "Core-MM")
|
||||||
|
if (NOT TARGET Bluelib::Core)
|
||||||
|
message(FATAL_ERROR "Bluelib: Module 'Core-MM' depends on 'Core', which was not specified in find_package()")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
target_link_libraries(Bluelib::Core-MM INTERFACE Bluelib::Core)
|
||||||
|
endif ()
|
||||||
|
endforeach (component)
|
||||||
|
endif()
|
||||||
7
toolchain/ifc/CMakeLists.txt
Normal file
7
toolchain/ifc/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
file(GLOB sources
|
||||||
|
*.c *.h
|
||||||
|
backend/c-mpc/*.c backend/c-mpc/*.h)
|
||||||
|
|
||||||
|
add_executable(ifc ${sources})
|
||||||
|
|
||||||
|
target_link_libraries(ifc Bluelib::Core Bluelib::Ds Bluelib::Cmd Bluelib::Io)
|
||||||
13
toolchain/ifc/backend.h
Normal file
13
toolchain/ifc/backend.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef IFC_BACKEND_H_
|
||||||
|
#define IFC_BACKEND_H_
|
||||||
|
|
||||||
|
struct interface_definition;
|
||||||
|
|
||||||
|
struct backend {
|
||||||
|
const char *b_name;
|
||||||
|
int (*b_emit)(const struct interface_definition *);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct backend *c_mpc_backend(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
1457
toolchain/ifc/backend/c-mpc/backend.c
Normal file
1457
toolchain/ifc/backend/c-mpc/backend.c
Normal file
File diff suppressed because it is too large
Load Diff
52
toolchain/ifc/ctx.c
Normal file
52
toolchain/ifc/ctx.c
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#include "ctx.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void init_builtin_types(struct ctx *ctx)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < TYPE_OTHER; i++) {
|
||||||
|
ctx->ctx_builtin_types[i].ty_id = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ctx *ctx_create(void)
|
||||||
|
{
|
||||||
|
struct ctx *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
init_builtin_types(out);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ctx_destroy(struct ctx *ctx)
|
||||||
|
{
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct type *ctx_get_type(struct ctx *ctx, const char *name)
|
||||||
|
{
|
||||||
|
if (!strcmp(name, "string")) {
|
||||||
|
return ctx_get_builtin_type(ctx, TYPE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(name, "int")) {
|
||||||
|
return ctx_get_builtin_type(ctx, TYPE_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct type *ctx_get_builtin_type(struct ctx *ctx, enum type_id id)
|
||||||
|
{
|
||||||
|
if (id >= TYPE_OTHER) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ctx->ctx_builtin_types[id];
|
||||||
|
}
|
||||||
18
toolchain/ifc/ctx.h
Normal file
18
toolchain/ifc/ctx.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef IFC_CTX_H_
|
||||||
|
#define IFC_CTX_H_
|
||||||
|
|
||||||
|
#include "type.h"
|
||||||
|
|
||||||
|
struct ctx {
|
||||||
|
struct type ctx_builtin_types[TYPE_OTHER];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct ctx *ctx_create(void);
|
||||||
|
extern void ctx_destroy(struct ctx *ctx);
|
||||||
|
|
||||||
|
extern const struct type *ctx_get_type(struct ctx *ctx, const char *name);
|
||||||
|
extern const struct type *ctx_get_builtin_type(
|
||||||
|
struct ctx *ctx,
|
||||||
|
enum type_id id);
|
||||||
|
|
||||||
|
#endif
|
||||||
12
toolchain/ifc/file-span.h
Normal file
12
toolchain/ifc/file-span.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef IFC_FILE_SPAN_H_
|
||||||
|
#define IFC_FILE_SPAN_H_
|
||||||
|
|
||||||
|
struct file_cell {
|
||||||
|
unsigned int c_row, c_col;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct file_span {
|
||||||
|
struct file_cell s_start, s_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
60
toolchain/ifc/interface.c
Normal file
60
toolchain/ifc/interface.c
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include "interface.h"
|
||||||
|
|
||||||
|
#include "msg.h"
|
||||||
|
|
||||||
|
#include <blue/ds/string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct interface_definition *interface_definition_create(const char *name)
|
||||||
|
{
|
||||||
|
struct interface_definition *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
out->if_name = b_strdup(name);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void interface_definition_destroy(struct interface_definition *iface)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_pop_front(&iface->if_msg);
|
||||||
|
while (entry) {
|
||||||
|
struct msg_definition *msg
|
||||||
|
= b_unbox(struct msg_definition, entry, msg_entry);
|
||||||
|
msg_definition_destroy(msg);
|
||||||
|
entry = b_queue_pop_front(&iface->if_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(iface->if_name);
|
||||||
|
free(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool interface_definition_has_msg(
|
||||||
|
const struct interface_definition *iface,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_first(&iface->if_msg);
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
|
struct msg_definition *msg
|
||||||
|
= b_unbox(struct msg_definition, entry, msg_entry);
|
||||||
|
if (!strcmp(msg->msg_name, name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void interface_definition_add_msg(
|
||||||
|
struct interface_definition *iface,
|
||||||
|
struct msg_definition *msg)
|
||||||
|
{
|
||||||
|
b_queue_push_back(&iface->if_msg, &msg->msg_entry);
|
||||||
|
}
|
||||||
24
toolchain/ifc/interface.h
Normal file
24
toolchain/ifc/interface.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef IFC_INTERFACE_H_
|
||||||
|
#define IFC_INTERFACE_H_
|
||||||
|
|
||||||
|
#include <blue/core/queue.h>
|
||||||
|
|
||||||
|
struct msg_definition;
|
||||||
|
|
||||||
|
struct interface_definition {
|
||||||
|
char *if_name;
|
||||||
|
b_queue if_msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct interface_definition *interface_definition_create(
|
||||||
|
const char *name);
|
||||||
|
extern void interface_definition_destroy(struct interface_definition *iface);
|
||||||
|
|
||||||
|
extern bool interface_definition_has_msg(
|
||||||
|
const struct interface_definition *iface,
|
||||||
|
const char *name);
|
||||||
|
extern void interface_definition_add_msg(
|
||||||
|
struct interface_definition *iface,
|
||||||
|
struct msg_definition *msg);
|
||||||
|
|
||||||
|
#endif
|
||||||
740
toolchain/ifc/lex.c
Normal file
740
toolchain/ifc/lex.c
Normal file
@@ -0,0 +1,740 @@
|
|||||||
|
#include "lex.h"
|
||||||
|
|
||||||
|
#include "line-source.h"
|
||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
#include <blue/core/hash.h>
|
||||||
|
#include <blue/core/misc.h>
|
||||||
|
#include <blue/core/queue.h>
|
||||||
|
#include <blue/ds/dict.h>
|
||||||
|
#include <blue/ds/number.h>
|
||||||
|
#include <blue/ds/string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
|
#define LINEBUF_DEFAULT_CAPACITY 1024
|
||||||
|
|
||||||
|
#define LEX_TOKEN_DEF(i, n) {.id = (i), .name = (n)}
|
||||||
|
|
||||||
|
#define IS_VALID_IDENT_CHAR(c) \
|
||||||
|
(b_wchar_is_alnum(c) || c == '.' || c == '-' || c == '_')
|
||||||
|
#define IS_VALID_IDENT_START_CHAR(c) \
|
||||||
|
(b_wchar_is_alpha(c) || c == '.' || c == '_')
|
||||||
|
#define IS_VALID_REG_START_CHAR(c) (b_wchar_is_alnum(c) || c == '.' || c == '_')
|
||||||
|
|
||||||
|
static struct lex_token_def symbols[] = {
|
||||||
|
LEX_TOKEN_DEF(SYM_COMMA, ","),
|
||||||
|
LEX_TOKEN_DEF(SYM_HYPHEN, "-"),
|
||||||
|
LEX_TOKEN_DEF(SYM_LEFT_BRACE, "{"),
|
||||||
|
LEX_TOKEN_DEF(SYM_RIGHT_BRACE, "}"),
|
||||||
|
LEX_TOKEN_DEF(SYM_LEFT_PAREN, "("),
|
||||||
|
LEX_TOKEN_DEF(SYM_RIGHT_PAREN, ")"),
|
||||||
|
LEX_TOKEN_DEF(SYM_SEMICOLON, ";"),
|
||||||
|
LEX_TOKEN_DEF(SYM_HYPHEN_RIGHT_ANGLE, "->"),
|
||||||
|
};
|
||||||
|
static const size_t nr_symbols = sizeof symbols / sizeof symbols[0];
|
||||||
|
|
||||||
|
static struct lex_token_def keywords[] = {
|
||||||
|
LEX_TOKEN_DEF(KW_INTERFACE, "interface"),
|
||||||
|
LEX_TOKEN_DEF(KW_MSG, "msg"),
|
||||||
|
};
|
||||||
|
static const size_t nr_keywords = sizeof keywords / sizeof keywords[0];
|
||||||
|
|
||||||
|
static struct lex_symbol_node *get_symbol_node(
|
||||||
|
struct lex_symbol_node *node,
|
||||||
|
char c)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_first(&node->s_children);
|
||||||
|
while (entry) {
|
||||||
|
struct lex_symbol_node *child
|
||||||
|
= b_unbox(struct lex_symbol_node, entry, s_entry);
|
||||||
|
if (child->s_char == c) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static b_string *get_temp_string(struct lex *lex)
|
||||||
|
{
|
||||||
|
if (!lex->lex_temp) {
|
||||||
|
lex->lex_temp = b_string_create();
|
||||||
|
}
|
||||||
|
|
||||||
|
b_string_clear(lex->lex_temp);
|
||||||
|
return lex->lex_temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status put_symbol(
|
||||||
|
struct lex_symbol_node *tree,
|
||||||
|
struct lex_token_def *sym)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; sym->name[i]; i++) {
|
||||||
|
char c = sym->name[i];
|
||||||
|
struct lex_symbol_node *child = get_symbol_node(tree, c);
|
||||||
|
if (child) {
|
||||||
|
tree = child;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
child = malloc(sizeof *child);
|
||||||
|
if (!child) {
|
||||||
|
return ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(child, 0x0, sizeof *child);
|
||||||
|
|
||||||
|
child->s_def = NULL;
|
||||||
|
child->s_char = c;
|
||||||
|
|
||||||
|
b_queue_push_back(&tree->s_children, &child->s_entry);
|
||||||
|
tree = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree->s_def = sym;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_symbol_tree(struct lex_symbol_node *tree)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_first(&tree->s_children);
|
||||||
|
while (entry) {
|
||||||
|
struct lex_symbol_node *node
|
||||||
|
= b_unbox(struct lex_symbol_node, entry, s_entry);
|
||||||
|
b_queue_entry *next = b_queue_next(entry);
|
||||||
|
b_queue_delete(&tree->s_children, entry);
|
||||||
|
|
||||||
|
destroy_symbol_tree(node);
|
||||||
|
|
||||||
|
entry = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct lex_symbol_node *build_symbol_tree(void)
|
||||||
|
{
|
||||||
|
struct lex_symbol_node *root = malloc(sizeof *root);
|
||||||
|
if (!root) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(root, 0x0, sizeof *root);
|
||||||
|
root->s_def = NULL;
|
||||||
|
|
||||||
|
enum status status = SUCCESS;
|
||||||
|
for (size_t i = 0; i < nr_symbols; i++) {
|
||||||
|
status = put_symbol(root, &symbols[i]);
|
||||||
|
|
||||||
|
if (status != SUCCESS) {
|
||||||
|
destroy_symbol_tree(root);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lex *lex_create(struct line_source *src)
|
||||||
|
{
|
||||||
|
struct lex *lex = malloc(sizeof *lex);
|
||||||
|
if (!lex) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(lex, 0x0, sizeof *lex);
|
||||||
|
|
||||||
|
lex->lex_status = SUCCESS;
|
||||||
|
lex->lex_source = src;
|
||||||
|
|
||||||
|
lex->lex_sym_tree = build_symbol_tree();
|
||||||
|
if (!lex->lex_sym_tree) {
|
||||||
|
lex_destroy(lex);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lex_destroy(struct lex *lex)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_first(&lex->lex_queue);
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
|
struct token *tok = b_unbox(struct token, entry, tok_entry);
|
||||||
|
b_queue_entry *next = b_queue_next(entry);
|
||||||
|
b_queue_delete(&lex->lex_queue, entry);
|
||||||
|
|
||||||
|
token_destroy(tok);
|
||||||
|
|
||||||
|
entry = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lex->lex_sym_tree) {
|
||||||
|
destroy_symbol_tree(lex->lex_sym_tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lex->lex_temp) {
|
||||||
|
b_string_unref(lex->lex_temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum status lex_get_status(const struct lex *lex)
|
||||||
|
{
|
||||||
|
return lex->lex_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct line_source *lex_get_line_source(const struct lex *lex)
|
||||||
|
{
|
||||||
|
return lex->lex_source;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct file_cell *lex_get_cursor(const struct lex *lex)
|
||||||
|
{
|
||||||
|
return &lex->lex_source->s_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool char_can_begin_symbol(char c)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < nr_symbols; i++) {
|
||||||
|
if (symbols[i].name[0] == c) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct token *create_token(enum token_type type)
|
||||||
|
{
|
||||||
|
struct token *tok = malloc(sizeof *tok);
|
||||||
|
if (!tok) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(tok, 0x0, sizeof *tok);
|
||||||
|
|
||||||
|
tok->tok_type = type;
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_token_start(struct lex *lex)
|
||||||
|
{
|
||||||
|
lex->lex_token_start = *line_source_get_cursor(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_token_end(struct lex *lex)
|
||||||
|
{
|
||||||
|
lex->lex_token_end = *line_source_get_cursor(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status push_token(struct lex *lex, struct token *tok)
|
||||||
|
{
|
||||||
|
tok->tok_location.s_start = lex->lex_token_start;
|
||||||
|
tok->tok_location.s_end = lex->lex_token_end;
|
||||||
|
|
||||||
|
b_queue_push_back(&lex->lex_queue, &tok->tok_entry);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status push_symbol(struct lex *lex, enum token_symbol sym)
|
||||||
|
{
|
||||||
|
struct token *tok = malloc(sizeof *tok);
|
||||||
|
if (!tok) {
|
||||||
|
return ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(tok, 0x0, sizeof *tok);
|
||||||
|
|
||||||
|
tok->tok_type = TOK_SYMBOL;
|
||||||
|
tok->tok_value_type = TOK_V_SYMBOL;
|
||||||
|
tok->tok_sym = sym;
|
||||||
|
return push_token(lex, tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status push_keyword(struct lex *lex, enum token_keyword kw)
|
||||||
|
{
|
||||||
|
struct token *tok = malloc(sizeof *tok);
|
||||||
|
if (!tok) {
|
||||||
|
return ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(tok, 0x0, sizeof *tok);
|
||||||
|
|
||||||
|
tok->tok_type = TOK_KEYWORD;
|
||||||
|
tok->tok_value_type = TOK_V_KEYWORD;
|
||||||
|
tok->tok_kw = kw;
|
||||||
|
return push_token(lex, tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status push_string_token(
|
||||||
|
struct lex *lex,
|
||||||
|
enum token_type type,
|
||||||
|
char *s)
|
||||||
|
{
|
||||||
|
struct token *tok = malloc(sizeof *tok);
|
||||||
|
if (!tok) {
|
||||||
|
return ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ep = NULL;
|
||||||
|
long long v = strtoll(s, &ep, 10);
|
||||||
|
|
||||||
|
memset(tok, 0x0, sizeof *tok);
|
||||||
|
|
||||||
|
tok->tok_type = type;
|
||||||
|
|
||||||
|
if (*ep == '\0') {
|
||||||
|
tok->tok_int = v;
|
||||||
|
tok->tok_value_type = TOK_V_INT;
|
||||||
|
free(s);
|
||||||
|
} else {
|
||||||
|
tok->tok_str = s;
|
||||||
|
tok->tok_value_type = TOK_V_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return push_token(lex, tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status push_int(struct lex *lex, unsigned long long v)
|
||||||
|
{
|
||||||
|
struct token *tok = malloc(sizeof *tok);
|
||||||
|
if (!tok) {
|
||||||
|
return ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(tok, 0x0, sizeof *tok);
|
||||||
|
|
||||||
|
tok->tok_type = TOK_INT;
|
||||||
|
tok->tok_value_type = TOK_V_INT;
|
||||||
|
tok->tok_int = v;
|
||||||
|
return push_token(lex, tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status read_line_comment(struct lex *lex)
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
b_wchar c = line_source_getc(lex->lex_source);
|
||||||
|
|
||||||
|
if (c == -ERR_EOF || c == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c < 0) {
|
||||||
|
return -c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status read_number(struct lex *lex, bool negate)
|
||||||
|
{
|
||||||
|
int token_len = 0;
|
||||||
|
int base = 10;
|
||||||
|
int dots = 0;
|
||||||
|
b_string *str = get_temp_string(lex);
|
||||||
|
|
||||||
|
if (!negate) {
|
||||||
|
set_token_start(lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
b_wchar c = line_source_peekc(lex->lex_source);
|
||||||
|
if (c == -ERR_EOF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c < 0) {
|
||||||
|
return -c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '_') {
|
||||||
|
token_len++;
|
||||||
|
set_token_end(lex);
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '.') {
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_wchar_is_space(c) || b_wchar_is_punct(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 'x' && token_len == 1) {
|
||||||
|
base = 16;
|
||||||
|
token_len++;
|
||||||
|
set_token_end(lex);
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 'b' && token_len == 1) {
|
||||||
|
base = 2;
|
||||||
|
token_len++;
|
||||||
|
set_token_end(lex);
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base == 2 && c != '0' && c != '1') {
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base == 10 && !isdigit(c)) {
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base == 16 && !isxdigit(c)) {
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_string_append_wc(str, c);
|
||||||
|
set_token_end(lex);
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
token_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token_len == 1 && base == 7) {
|
||||||
|
return push_int(lex, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *s = b_string_ptr(str);
|
||||||
|
char *ep = NULL;
|
||||||
|
|
||||||
|
/* negative numbers will be lexed as a hyphen followed by a positive
|
||||||
|
* number. */
|
||||||
|
|
||||||
|
unsigned long long v = strtoull(s, &ep, base);
|
||||||
|
|
||||||
|
if (*ep != '\0') {
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negate) {
|
||||||
|
v *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return push_int(lex, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum token_keyword find_keyword(const char *s)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < nr_keywords; i++) {
|
||||||
|
if (!strcmp(keywords[i].name, s)) {
|
||||||
|
return keywords[i].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KW_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status read_ident(struct lex *lex, enum token_type type)
|
||||||
|
{
|
||||||
|
int dots = 0;
|
||||||
|
b_string *str = get_temp_string(lex);
|
||||||
|
b_wchar prev = 0;
|
||||||
|
|
||||||
|
if (type == TOK_NONE) {
|
||||||
|
set_token_start(lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
b_wchar c = line_source_peekc(lex->lex_source);
|
||||||
|
|
||||||
|
if ((c == '.' || c == '-') && prev == c) {
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '.') {
|
||||||
|
dots++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_VALID_IDENT_CHAR(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = c;
|
||||||
|
b_string_append_wc(str, c);
|
||||||
|
set_token_end(lex);
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == TOK_NONE) {
|
||||||
|
type = dots > 0 ? TOK_NAME : TOK_WORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *s = b_string_steal(str);
|
||||||
|
enum token_keyword kw = find_keyword(s);
|
||||||
|
if (kw != KW_NONE) {
|
||||||
|
free(s);
|
||||||
|
return push_keyword(lex, kw);
|
||||||
|
}
|
||||||
|
|
||||||
|
return push_string_token(lex, type, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status read_string(struct lex *lex)
|
||||||
|
{
|
||||||
|
b_string *str = get_temp_string(lex);
|
||||||
|
|
||||||
|
b_wchar c = line_source_peekc(lex->lex_source);
|
||||||
|
bool esc = false;
|
||||||
|
|
||||||
|
if (c != '"') {
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
b_wchar c = line_source_peekc(lex->lex_source);
|
||||||
|
|
||||||
|
if (esc) {
|
||||||
|
switch (c) {
|
||||||
|
case '\\':
|
||||||
|
case '"':
|
||||||
|
b_string_append_wc(str, c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
esc = false;
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\\') {
|
||||||
|
esc = true;
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '"') {
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_string_append_wc(str, c);
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *s = b_string_steal(str);
|
||||||
|
return push_string_token(lex, TOK_STRING, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status read_symbol(struct lex *lex)
|
||||||
|
{
|
||||||
|
struct lex_symbol_node *node = lex->lex_sym_tree;
|
||||||
|
set_token_start(lex);
|
||||||
|
b_wchar prev = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
b_wchar c = line_source_peekc(lex->lex_source);
|
||||||
|
if (c < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lex_symbol_node *next = get_symbol_node(node, c);
|
||||||
|
if (!next) {
|
||||||
|
prev = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = next;
|
||||||
|
set_token_end(lex);
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
prev = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node || node->s_def == NULL) {
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->s_def->id == SYM_HYPHEN && isdigit(prev)) {
|
||||||
|
return read_number(lex, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return push_symbol(lex, node->s_def->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void skip_whitespace(struct lex *lex)
|
||||||
|
{
|
||||||
|
b_wchar c = line_source_peekc(lex->lex_source);
|
||||||
|
|
||||||
|
while (b_wchar_is_space(c)) {
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
c = line_source_peekc(lex->lex_source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool should_skip(b_wchar c, bool skip_linefeeds)
|
||||||
|
{
|
||||||
|
bool skip = b_wchar_is_space(c);
|
||||||
|
|
||||||
|
if (!skip_linefeeds) {
|
||||||
|
skip = (skip && c != '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void skip_ignored_chars(struct lex *lex, bool include_linefeeds)
|
||||||
|
{
|
||||||
|
b_wchar c = line_source_peekc(lex->lex_source);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
while (should_skip(c, include_linefeeds)) {
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
c = line_source_peekc(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c != '#') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
c = line_source_peekc(lex->lex_source);
|
||||||
|
|
||||||
|
while (c != '\n') {
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
c = line_source_peekc(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
c = line_source_peekc(lex->lex_source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status pump_tokens(struct lex *lex)
|
||||||
|
{
|
||||||
|
b_wchar c = line_source_peekc(lex->lex_source);
|
||||||
|
|
||||||
|
if (c < 0) {
|
||||||
|
return -c;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (c == '#' || (b_wchar_is_space(c) && c != '\n')) {
|
||||||
|
skip_ignored_chars(lex, false);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = line_source_peekc(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\\') {
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
skip_ignored_chars(lex, true);
|
||||||
|
c = line_source_peekc(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
set_token_start(lex);
|
||||||
|
set_token_end(lex);
|
||||||
|
|
||||||
|
while (c == '\n') {
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
|
||||||
|
if (!line_source_input_available(lex->lex_source)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = line_source_peekc(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c < 0) {
|
||||||
|
return -c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (b_wchar_is_space(c) && c != '\n') {
|
||||||
|
line_source_getc(lex->lex_source);
|
||||||
|
c = line_source_peekc(lex->lex_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_VALID_IDENT_START_CHAR(c)) {
|
||||||
|
return read_ident(lex, TOK_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (char_can_begin_symbol(c)) {
|
||||||
|
return read_symbol(lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '"') {
|
||||||
|
return read_string(lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isdigit(c)) {
|
||||||
|
return read_number(lex, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct token *lex_peek(struct lex *lex)
|
||||||
|
{
|
||||||
|
enum status status = SUCCESS;
|
||||||
|
|
||||||
|
while (b_queue_empty(&lex->lex_queue)) {
|
||||||
|
status = pump_tokens(lex);
|
||||||
|
|
||||||
|
if (status != SUCCESS) {
|
||||||
|
lex->lex_status = status;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lex->lex_status = status;
|
||||||
|
|
||||||
|
b_queue_entry *entry = b_queue_first(&lex->lex_queue);
|
||||||
|
struct token *tok = b_unbox(struct token, entry, tok_entry);
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lex_advance(struct lex *lex)
|
||||||
|
{
|
||||||
|
enum status status = SUCCESS;
|
||||||
|
|
||||||
|
while (b_queue_empty(&lex->lex_queue)) {
|
||||||
|
status = pump_tokens(lex);
|
||||||
|
|
||||||
|
if (status != SUCCESS) {
|
||||||
|
lex->lex_status = status;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b_queue_entry *entry = b_queue_pop_front(&lex->lex_queue);
|
||||||
|
struct token *tok = b_unbox(struct token, entry, tok_entry);
|
||||||
|
token_destroy(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lex_tokens_available(struct lex *lex)
|
||||||
|
{
|
||||||
|
if (!b_queue_empty(&lex->lex_queue)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line_source_input_available(lex->lex_source)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
52
toolchain/ifc/lex.h
Normal file
52
toolchain/ifc/lex.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#ifndef IFC_LEX_H_
|
||||||
|
#define IFC_LEX_H_
|
||||||
|
|
||||||
|
#include "status.h"
|
||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
#include <blue/core/queue.h>
|
||||||
|
#include <blue/ds/dict.h>
|
||||||
|
#include <blue/ds/string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct lex {
|
||||||
|
struct lex_symbol_node *lex_sym_tree;
|
||||||
|
struct line_source *lex_source;
|
||||||
|
enum status lex_status;
|
||||||
|
|
||||||
|
b_queue lex_queue;
|
||||||
|
|
||||||
|
b_string *lex_temp;
|
||||||
|
b_queue lex_state;
|
||||||
|
unsigned int lex_brace_depth;
|
||||||
|
|
||||||
|
struct file_cell lex_token_start, lex_token_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lex_symbol_node {
|
||||||
|
char s_char;
|
||||||
|
struct lex_token_def *s_def;
|
||||||
|
|
||||||
|
b_queue_entry s_entry;
|
||||||
|
b_queue s_children;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lex_token_def {
|
||||||
|
int id;
|
||||||
|
const char *name;
|
||||||
|
uint64_t name_hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct token;
|
||||||
|
struct line_source;
|
||||||
|
|
||||||
|
extern struct lex *lex_create(struct line_source *src);
|
||||||
|
extern void lex_destroy(struct lex *lex);
|
||||||
|
|
||||||
|
extern enum status lex_get_status(const struct lex *lex);
|
||||||
|
extern struct line_source *lex_get_line_source(const struct lex *lex);
|
||||||
|
extern const struct file_cell *lex_get_cursor(const struct lex *lex);
|
||||||
|
extern struct token *lex_peek(struct lex *lex);
|
||||||
|
extern void lex_advance(struct lex *lex);
|
||||||
|
|
||||||
|
#endif
|
||||||
164
toolchain/ifc/line-source.c
Normal file
164
toolchain/ifc/line-source.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
#include "line-source.h"
|
||||||
|
|
||||||
|
enum status line_source_init(
|
||||||
|
struct line_source *src,
|
||||||
|
const char *path,
|
||||||
|
b_stream *stream)
|
||||||
|
{
|
||||||
|
memset(src, 0x0, sizeof *src);
|
||||||
|
|
||||||
|
src->s_lines = b_array_create();
|
||||||
|
|
||||||
|
if (!src->s_lines) {
|
||||||
|
return ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
src->s_stream = stream;
|
||||||
|
src->s_path = path;
|
||||||
|
src->s_cursor.c_col = 1;
|
||||||
|
src->s_cursor.c_row = 1;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void line_source_cleanup(struct line_source *src)
|
||||||
|
{
|
||||||
|
if (src->s_linebuf_ptr) {
|
||||||
|
b_iterator_unref(src->s_linebuf_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src->s_lines) {
|
||||||
|
b_array_unref(src->s_lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(src, 0x0, sizeof *src);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *line_source_get_path(const struct line_source *src)
|
||||||
|
{
|
||||||
|
return src->s_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct file_cell *line_source_get_cursor(const struct line_source *src)
|
||||||
|
{
|
||||||
|
return &src->s_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum status refill_linebuf(struct line_source *src)
|
||||||
|
{
|
||||||
|
if (!src->s_stream) {
|
||||||
|
return ERR_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src->s_linebuf_ptr) {
|
||||||
|
b_iterator_unref(src->s_linebuf_ptr);
|
||||||
|
src->s_linebuf_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_stringstream *s = b_stringstream_create();
|
||||||
|
|
||||||
|
b_status status = b_stream_read_line_s(src->s_stream, s);
|
||||||
|
|
||||||
|
if (status == B_ERR_NO_DATA) {
|
||||||
|
return ERR_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!B_OK(status)) {
|
||||||
|
return ERR_INTERNAL_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_string *line = b_string_create();
|
||||||
|
b_string_replace_all_with_stringstream(line, s);
|
||||||
|
b_stringstream_unref(s);
|
||||||
|
|
||||||
|
b_array_append(src->s_lines, line);
|
||||||
|
b_string_unref(line);
|
||||||
|
|
||||||
|
src->s_linebuf = line;
|
||||||
|
src->s_linebuf_ptr = b_iterator_begin(src->s_linebuf);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int peek(struct line_source *src)
|
||||||
|
{
|
||||||
|
enum status status = SUCCESS;
|
||||||
|
|
||||||
|
if (!src->s_linebuf_ptr || !b_iterator_is_valid(src->s_linebuf_ptr)) {
|
||||||
|
status = refill_linebuf(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != SUCCESS) {
|
||||||
|
return -status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_string_get_size(src->s_linebuf, B_STRLEN_NORMAL) == 0) {
|
||||||
|
return -ERR_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_wchar c = b_iterator_get_value(src->s_linebuf_ptr).v_int;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int advance(struct line_source *src)
|
||||||
|
{
|
||||||
|
enum status status = SUCCESS;
|
||||||
|
|
||||||
|
if (!b_iterator_is_valid(src->s_linebuf_ptr)) {
|
||||||
|
status = refill_linebuf(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != SUCCESS) {
|
||||||
|
return -status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b_string_get_size(src->s_linebuf, B_STRLEN_NORMAL) == 0) {
|
||||||
|
return -ERR_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_wchar c = b_iterator_get_value(src->s_linebuf_ptr).v_int;
|
||||||
|
b_iterator_move_next(src->s_linebuf_ptr);
|
||||||
|
|
||||||
|
src->s_cursor.c_col++;
|
||||||
|
if (c == '\n') {
|
||||||
|
src->s_cursor.c_col = 1;
|
||||||
|
src->s_cursor.c_row++;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_wchar line_source_peekc(struct line_source *src)
|
||||||
|
{
|
||||||
|
return peek(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
b_wchar line_source_getc(struct line_source *src)
|
||||||
|
{
|
||||||
|
return advance(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum status line_source_get_row(
|
||||||
|
struct line_source *src,
|
||||||
|
size_t row,
|
||||||
|
const b_string **out)
|
||||||
|
{
|
||||||
|
if (row == 0) {
|
||||||
|
return ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
row--;
|
||||||
|
|
||||||
|
if (row >= b_array_size(src->s_lines)) {
|
||||||
|
return ERR_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_string *line = b_array_at(src->s_lines, row);
|
||||||
|
*out = line;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool line_source_input_available(struct line_source *src)
|
||||||
|
{
|
||||||
|
return src->s_linebuf_ptr && b_iterator_is_valid(src->s_linebuf_ptr);
|
||||||
|
}
|
||||||
39
toolchain/ifc/line-source.h
Normal file
39
toolchain/ifc/line-source.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef LINE_SOURCE_H_
|
||||||
|
#define LINE_SOURCE_H_
|
||||||
|
|
||||||
|
#include "file-span.h"
|
||||||
|
#include "status.h"
|
||||||
|
|
||||||
|
#include <blue/core/stream.h>
|
||||||
|
#include <blue/ds/array.h>
|
||||||
|
#include <blue/ds/string.h>
|
||||||
|
|
||||||
|
struct line_source {
|
||||||
|
b_stream *s_stream;
|
||||||
|
const char *s_path;
|
||||||
|
b_string *s_linebuf;
|
||||||
|
b_iterator *s_linebuf_ptr;
|
||||||
|
b_array *s_lines;
|
||||||
|
|
||||||
|
struct file_cell s_cursor;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum status line_source_init(
|
||||||
|
struct line_source *src,
|
||||||
|
const char *path,
|
||||||
|
b_stream *stream);
|
||||||
|
extern void line_source_cleanup(struct line_source *src);
|
||||||
|
|
||||||
|
extern const char *line_source_get_path(const struct line_source *src);
|
||||||
|
extern const struct file_cell *line_source_get_cursor(
|
||||||
|
const struct line_source *src);
|
||||||
|
extern b_wchar line_source_peekc(struct line_source *src);
|
||||||
|
extern b_wchar line_source_getc(struct line_source *src);
|
||||||
|
extern enum status line_source_get_row(
|
||||||
|
struct line_source *src,
|
||||||
|
size_t row,
|
||||||
|
const b_string **out);
|
||||||
|
|
||||||
|
extern bool line_source_input_available(struct line_source *src);
|
||||||
|
|
||||||
|
#endif
|
||||||
166
toolchain/ifc/main.c
Normal file
166
toolchain/ifc/main.c
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
#include "backend.h"
|
||||||
|
#include "ctx.h"
|
||||||
|
#include "interface.h"
|
||||||
|
#include "lex.h"
|
||||||
|
#include "line-source.h"
|
||||||
|
#include "msg.h"
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
|
#include <blue/cmd.h>
|
||||||
|
#include <blue/io/file.h>
|
||||||
|
#include <blue/io/path.h>
|
||||||
|
|
||||||
|
#define CMD_ID 0
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARG_SRCPATH,
|
||||||
|
OPT_BACKEND,
|
||||||
|
OPT_BACKEND_ARG_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
return b_command_dispatch(CMD_ID, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_msg(struct msg_definition *msg)
|
||||||
|
{
|
||||||
|
printf(" msg: %s\n", msg->msg_name);
|
||||||
|
|
||||||
|
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
||||||
|
while (entry) {
|
||||||
|
struct msg_parameter *param
|
||||||
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
|
|
||||||
|
printf(" param:");
|
||||||
|
type_print(param->p_type);
|
||||||
|
printf(" %s\n", param->p_name);
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_first(&msg->msg_results);
|
||||||
|
while (entry) {
|
||||||
|
struct msg_parameter *param
|
||||||
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
|
|
||||||
|
printf(" result:");
|
||||||
|
type_print(param->p_type);
|
||||||
|
printf(" %s\n", param->p_name);
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_interface(struct interface_definition *iface)
|
||||||
|
{
|
||||||
|
printf("interface: %s\n", iface->if_name);
|
||||||
|
b_queue_entry *entry = b_queue_first(&iface->if_msg);
|
||||||
|
while (entry) {
|
||||||
|
struct msg_definition *msg
|
||||||
|
= b_unbox(struct msg_definition, entry, msg_entry);
|
||||||
|
print_msg(msg);
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ifc(const b_command *self, const b_arglist *opt, const b_array *args)
|
||||||
|
{
|
||||||
|
const char *path = NULL;
|
||||||
|
b_arglist_get_string(opt, B_COMMAND_INVALID_ID, ARG_SRCPATH, 0, &path);
|
||||||
|
if (!path) {
|
||||||
|
b_arglist_report_missing_args(
|
||||||
|
opt,
|
||||||
|
B_COMMAND_INVALID_ID,
|
||||||
|
ARG_SRCPATH,
|
||||||
|
0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_file *file = NULL;
|
||||||
|
b_result result
|
||||||
|
= b_file_open(NULL, B_RV_PATH(path), B_FILE_READ_ONLY, &file);
|
||||||
|
if (b_result_is_error(result)) {
|
||||||
|
b_throw(result);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct line_source src;
|
||||||
|
line_source_init(&src, path, file);
|
||||||
|
|
||||||
|
struct ctx *ctx = ctx_create();
|
||||||
|
struct lex *lex = lex_create(&src);
|
||||||
|
#if 0
|
||||||
|
struct token *tok = lex_peek(lex);
|
||||||
|
while (tok) {
|
||||||
|
printf("%s", token_type_to_string(tok->tok_type));
|
||||||
|
|
||||||
|
switch (tok->tok_value_type) {
|
||||||
|
case TOK_V_INT:
|
||||||
|
printf(" %lld", tok->tok_int);
|
||||||
|
break;
|
||||||
|
case TOK_V_STRING:
|
||||||
|
printf(" %s", tok->tok_str);
|
||||||
|
break;
|
||||||
|
case TOK_V_SYMBOL:
|
||||||
|
printf(" %s", token_symbol_to_string(tok->tok_sym));
|
||||||
|
break;
|
||||||
|
case TOK_V_KEYWORD:
|
||||||
|
printf(" %s", token_keyword_to_string(tok->tok_kw));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
lex_advance(lex);
|
||||||
|
tok = lex_peek(lex);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct interface_definition *iface
|
||||||
|
= parse_interface_definition(ctx, lex);
|
||||||
|
if (!iface) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct backend *backend = c_mpc_backend();
|
||||||
|
int err = backend->b_emit(iface);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND(CMD_ID, B_COMMAND_INVALID_ID)
|
||||||
|
{
|
||||||
|
B_COMMAND_NAME("ifc");
|
||||||
|
B_COMMAND_DESC("interface definition compiler.");
|
||||||
|
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
|
||||||
|
B_COMMAND_FUNCTION(ifc);
|
||||||
|
B_COMMAND_HELP_OPTION();
|
||||||
|
|
||||||
|
B_COMMAND_ARG(ARG_SRCPATH)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("source-file");
|
||||||
|
B_ARG_DESC("the interface file to compile.");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_OPTION(OPT_BACKEND)
|
||||||
|
{
|
||||||
|
B_OPTION_LONG_NAME("backend");
|
||||||
|
B_OPTION_SHORT_NAME('b');
|
||||||
|
B_OPTION_DESC("which backend to use.");
|
||||||
|
B_OPTION_ARG(OPT_BACKEND_ARG_NAME)
|
||||||
|
{
|
||||||
|
B_ARG_NAME("backend-name");
|
||||||
|
B_ARG_NR_VALUES(1);
|
||||||
|
B_ARG_ALLOWED_VALUES("c-mpc");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
B_COMMAND_USAGE()
|
||||||
|
{
|
||||||
|
B_COMMAND_USAGE_ARG(ARG_SRCPATH);
|
||||||
|
B_COMMAND_USAGE_OPT(OPT_BACKEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
113
toolchain/ifc/msg.c
Normal file
113
toolchain/ifc/msg.c
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#include "msg.h"
|
||||||
|
|
||||||
|
#include <blue/ds/string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct msg_definition *msg_definition_create(const char *name)
|
||||||
|
{
|
||||||
|
struct msg_definition *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
out->msg_name = b_strdup(name);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void msg_definition_destroy(struct msg_definition *msg)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_pop_front(&msg->msg_params);
|
||||||
|
while (entry) {
|
||||||
|
struct msg_parameter *param
|
||||||
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
|
free(param->p_name);
|
||||||
|
free(param);
|
||||||
|
entry = b_queue_pop_front(&msg->msg_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_pop_front(&msg->msg_results);
|
||||||
|
while (entry) {
|
||||||
|
struct msg_parameter *param
|
||||||
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
|
free(param->p_name);
|
||||||
|
free(param);
|
||||||
|
entry = b_queue_pop_front(&msg->msg_results);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(msg->msg_name);
|
||||||
|
free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool msg_definition_has_param(struct msg_definition *msg, const char *name)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
||||||
|
while (entry) {
|
||||||
|
struct msg_parameter *param
|
||||||
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
|
if (!strcmp(param->p_name, name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool msg_definition_has_result(struct msg_definition *msg, const char *name)
|
||||||
|
{
|
||||||
|
b_queue_entry *entry = b_queue_first(&msg->msg_results);
|
||||||
|
while (entry) {
|
||||||
|
struct msg_parameter *param
|
||||||
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
|
if (!strcmp(param->p_name, name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int msg_definition_add_param(
|
||||||
|
struct msg_definition *msg,
|
||||||
|
const struct type *type,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct msg_parameter *param = malloc(sizeof *param);
|
||||||
|
if (!param) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(param, 0x0, sizeof *param);
|
||||||
|
|
||||||
|
param->p_type = type;
|
||||||
|
param->p_name = b_strdup(name);
|
||||||
|
|
||||||
|
b_queue_push_back(&msg->msg_params, ¶m->p_entry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int msg_definition_add_result(
|
||||||
|
struct msg_definition *msg,
|
||||||
|
const struct type *type,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct msg_parameter *param = malloc(sizeof *param);
|
||||||
|
if (!param) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(param, 0x0, sizeof *param);
|
||||||
|
|
||||||
|
param->p_type = type;
|
||||||
|
param->p_name = b_strdup(name);
|
||||||
|
|
||||||
|
b_queue_push_back(&msg->msg_results, ¶m->p_entry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
41
toolchain/ifc/msg.h
Normal file
41
toolchain/ifc/msg.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#ifndef IFC_MSG_H_
|
||||||
|
#define IFC_MSG_H_
|
||||||
|
|
||||||
|
#include <blue/core/queue.h>
|
||||||
|
|
||||||
|
struct type;
|
||||||
|
|
||||||
|
struct msg_parameter {
|
||||||
|
char *p_name;
|
||||||
|
const struct type *p_type;
|
||||||
|
b_queue_entry p_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msg_definition {
|
||||||
|
char *msg_name;
|
||||||
|
b_queue_entry msg_entry;
|
||||||
|
|
||||||
|
b_queue msg_params;
|
||||||
|
b_queue msg_results;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct msg_definition *msg_definition_create(const char *name);
|
||||||
|
extern void msg_definition_destroy(struct msg_definition *msg);
|
||||||
|
|
||||||
|
extern bool msg_definition_has_param(
|
||||||
|
struct msg_definition *msg,
|
||||||
|
const char *name);
|
||||||
|
extern bool msg_definition_has_result(
|
||||||
|
struct msg_definition *msg,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
extern int msg_definition_add_param(
|
||||||
|
struct msg_definition *msg,
|
||||||
|
const struct type *type,
|
||||||
|
const char *name);
|
||||||
|
extern int msg_definition_add_result(
|
||||||
|
struct msg_definition *msg,
|
||||||
|
const struct type *type,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
#endif
|
||||||
287
toolchain/ifc/parse.c
Normal file
287
toolchain/ifc/parse.c
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
#include "ctx.h"
|
||||||
|
#include "interface.h"
|
||||||
|
#include "lex.h"
|
||||||
|
#include "msg.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define report_error(...) fprintf(stderr, __VA_ARGS__)
|
||||||
|
|
||||||
|
static bool peek_keyword(struct lex *lex, enum token_keyword kw)
|
||||||
|
{
|
||||||
|
struct token *tok = lex_peek(lex);
|
||||||
|
return (tok && tok->tok_type == TOK_KEYWORD && tok->tok_kw == kw);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_keyword(struct lex *lex, enum token_keyword kw)
|
||||||
|
{
|
||||||
|
struct token *tok = lex_peek(lex);
|
||||||
|
if (!tok || tok->tok_type != TOK_KEYWORD || tok->tok_kw != kw) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lex_advance(lex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_symbol(struct lex *lex, enum token_symbol sym)
|
||||||
|
{
|
||||||
|
struct token *tok = lex_peek(lex);
|
||||||
|
if (!tok || tok->tok_type != TOK_SYMBOL || tok->tok_sym != sym) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lex_advance(lex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_word(struct lex *lex, char **out)
|
||||||
|
{
|
||||||
|
struct token *tok = lex_peek(lex);
|
||||||
|
if (!tok || tok->tok_type != TOK_WORD) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = tok->tok_str;
|
||||||
|
tok->tok_str = NULL;
|
||||||
|
lex_advance(lex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
|
||||||
|
{
|
||||||
|
struct msg_definition *msg = NULL;
|
||||||
|
|
||||||
|
if (!parse_keyword(lex, KW_MSG)) {
|
||||||
|
report_error("expected `msg` keyword\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *msg_name = NULL;
|
||||||
|
if (!parse_word(lex, &msg_name)) {
|
||||||
|
report_error("expected message identifier\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = msg_definition_create(msg_name);
|
||||||
|
free(msg_name);
|
||||||
|
|
||||||
|
if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
|
||||||
|
report_error("expected `(` after message identifier\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
bool ok = true;
|
||||||
|
while (ok) {
|
||||||
|
if (parse_symbol(lex, SYM_RIGHT_PAREN)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
|
||||||
|
report_error("expected `,` after message parameter\n");
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *type_name;
|
||||||
|
if (!parse_word(lex, &type_name)) {
|
||||||
|
report_error("expected message parameter type\n");
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct type *type = ctx_get_type(ctx, type_name);
|
||||||
|
if (!type) {
|
||||||
|
report_error(
|
||||||
|
"message parameter has unknown type "
|
||||||
|
"'%s'\n",
|
||||||
|
type_name);
|
||||||
|
free(type_name);
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(type_name);
|
||||||
|
|
||||||
|
char *param_name;
|
||||||
|
if (!parse_word(lex, ¶m_name)) {
|
||||||
|
report_error("expected message parameter name\n");
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool duplicate = msg_definition_has_param(msg, param_name)
|
||||||
|
|| msg_definition_has_result(msg, param_name);
|
||||||
|
if (duplicate) {
|
||||||
|
free(param_name);
|
||||||
|
report_error(
|
||||||
|
"message has multiple parameters/results with "
|
||||||
|
"name '%s'\n",
|
||||||
|
param_name);
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_definition_add_param(msg, type, param_name);
|
||||||
|
free(param_name);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_symbol(lex, SYM_HYPHEN_RIGHT_ANGLE)) {
|
||||||
|
report_error("expected `->` after message parameter list\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
|
||||||
|
report_error("expected `(` for message results list\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (ok) {
|
||||||
|
if (parse_symbol(lex, SYM_RIGHT_PAREN)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
|
||||||
|
report_error(
|
||||||
|
"expected `,` or `)` after message result\n");
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *type_name;
|
||||||
|
if (!parse_word(lex, &type_name)) {
|
||||||
|
report_error("expected message result type\n");
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct type *type = ctx_get_type(ctx, type_name);
|
||||||
|
if (!type) {
|
||||||
|
report_error(
|
||||||
|
"message result has unknown type "
|
||||||
|
"'%s'\n",
|
||||||
|
type_name);
|
||||||
|
free(type_name);
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(type_name);
|
||||||
|
|
||||||
|
char *result_name;
|
||||||
|
if (!parse_word(lex, &result_name)) {
|
||||||
|
report_error("expected message parameter name\n");
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool duplicate = msg_definition_has_param(msg, result_name)
|
||||||
|
|| msg_definition_has_result(msg, result_name);
|
||||||
|
if (duplicate) {
|
||||||
|
report_error(
|
||||||
|
"message has multiple parameters/results with "
|
||||||
|
"name '%s'\n",
|
||||||
|
result_name);
|
||||||
|
free(result_name);
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_definition_add_result(msg, type, result_name);
|
||||||
|
free(result_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_symbol(lex, SYM_SEMICOLON)) {
|
||||||
|
report_error("expected `;` after message definition\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (msg) {
|
||||||
|
msg_definition_destroy(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct interface_definition *parse_interface_definition(
|
||||||
|
struct ctx *ctx,
|
||||||
|
struct lex *lex)
|
||||||
|
{
|
||||||
|
struct interface_definition *iface = NULL;
|
||||||
|
|
||||||
|
if (!parse_keyword(lex, KW_INTERFACE)) {
|
||||||
|
report_error("expected `interface` keyword");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *if_name = NULL;
|
||||||
|
if (!parse_word(lex, &if_name)) {
|
||||||
|
report_error("expected interface identifier");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
iface = interface_definition_create(if_name);
|
||||||
|
free(if_name);
|
||||||
|
if (!iface) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_symbol(lex, SYM_LEFT_BRACE)) {
|
||||||
|
report_error("expected `{` after interface identifier");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
while (ok) {
|
||||||
|
if (parse_symbol(lex, SYM_RIGHT_BRACE)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek_keyword(lex, KW_MSG)) {
|
||||||
|
struct msg_definition *msg
|
||||||
|
= parse_msg_definition(ctx, lex);
|
||||||
|
if (!msg) {
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interface_definition_has_msg(
|
||||||
|
iface,
|
||||||
|
msg->msg_name)) {
|
||||||
|
msg_definition_destroy(msg);
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface_definition_add_msg(iface, msg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
report_error("expected `}` or message definition\n");
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return iface;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (iface) {
|
||||||
|
interface_definition_destroy(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
12
toolchain/ifc/parse.h
Normal file
12
toolchain/ifc/parse.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef IFC_PARSE_H_
|
||||||
|
#define IFC_PARSE_H_
|
||||||
|
|
||||||
|
struct ctx;
|
||||||
|
struct lex;
|
||||||
|
struct interface_definition;
|
||||||
|
|
||||||
|
extern struct interface_definition *parse_interface_definition(
|
||||||
|
struct ctx *ctx,
|
||||||
|
struct lex *lex);
|
||||||
|
|
||||||
|
#endif
|
||||||
20
toolchain/ifc/status.h
Normal file
20
toolchain/ifc/status.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef IFC_STATUS_H_
|
||||||
|
#define IFC_STATUS_H_
|
||||||
|
|
||||||
|
enum status {
|
||||||
|
SUCCESS = 0,
|
||||||
|
ERR_EOF,
|
||||||
|
ERR_BAD_SYNTAX,
|
||||||
|
ERR_BAD_FORMAT,
|
||||||
|
ERR_BAD_STATE,
|
||||||
|
ERR_INVALID_VALUE,
|
||||||
|
ERR_INVALID_ARGUMENT,
|
||||||
|
ERR_NO_MEMORY,
|
||||||
|
ERR_NO_ENTRY,
|
||||||
|
ERR_NO_DATA,
|
||||||
|
ERR_NAME_EXISTS,
|
||||||
|
ERR_NOT_SUPPORTED,
|
||||||
|
ERR_INTERNAL_FAILURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
63
toolchain/ifc/token.c
Normal file
63
toolchain/ifc/token.c
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
void token_destroy(struct token *tok)
|
||||||
|
{
|
||||||
|
switch (tok->tok_value_type) {
|
||||||
|
case TOK_V_STRING:
|
||||||
|
if (tok->tok_str) {
|
||||||
|
free(tok->tok_str);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ENUM_STR(x) \
|
||||||
|
case x: \
|
||||||
|
return #x
|
||||||
|
|
||||||
|
const char *token_type_to_string(enum token_type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
ENUM_STR(TOK_NONE);
|
||||||
|
ENUM_STR(TOK_INT);
|
||||||
|
ENUM_STR(TOK_SYMBOL);
|
||||||
|
ENUM_STR(TOK_WORD);
|
||||||
|
ENUM_STR(TOK_NAME);
|
||||||
|
ENUM_STR(TOK_STRING);
|
||||||
|
ENUM_STR(TOK_KEYWORD);
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *token_symbol_to_string(enum token_symbol sym)
|
||||||
|
{
|
||||||
|
switch (sym) {
|
||||||
|
ENUM_STR(SYM_NONE);
|
||||||
|
ENUM_STR(SYM_COMMA);
|
||||||
|
ENUM_STR(SYM_SEMICOLON);
|
||||||
|
ENUM_STR(SYM_HYPHEN);
|
||||||
|
ENUM_STR(SYM_LEFT_BRACE);
|
||||||
|
ENUM_STR(SYM_RIGHT_BRACE);
|
||||||
|
ENUM_STR(SYM_LEFT_PAREN);
|
||||||
|
ENUM_STR(SYM_RIGHT_PAREN);
|
||||||
|
ENUM_STR(SYM_HYPHEN_RIGHT_ANGLE);
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *token_keyword_to_string(enum token_keyword kw)
|
||||||
|
{
|
||||||
|
switch (kw) {
|
||||||
|
ENUM_STR(KW_NONE);
|
||||||
|
ENUM_STR(KW_INTERFACE);
|
||||||
|
ENUM_STR(KW_MSG);
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
70
toolchain/ifc/token.h
Normal file
70
toolchain/ifc/token.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#ifndef IFC_TOKEN_H_
|
||||||
|
#define IFC_TOKEN_H_
|
||||||
|
|
||||||
|
#include "file-span.h"
|
||||||
|
|
||||||
|
#include <blue/core/queue.h>
|
||||||
|
|
||||||
|
#define TOKEN_TYPE(tok) ((tok) ? (tok)->tok_type : TOK_NONE)
|
||||||
|
#define TOKEN_IS(tok, type) ((tok) && ((tok)->tok_type & (type)) != 0)
|
||||||
|
#define TOKEN_IS_SYMBOL(tok, sym) \
|
||||||
|
((tok) && (tok)->tok_type == TOK_SYMBOL && (tok)->tok_sym == (sym))
|
||||||
|
|
||||||
|
enum token_type {
|
||||||
|
TOK_NONE = 0,
|
||||||
|
TOK_SYMBOL = 0x0001u,
|
||||||
|
TOK_KEYWORD = 0x0002u,
|
||||||
|
TOK_WORD = 0x0004u,
|
||||||
|
TOK_NAME = 0x0008u,
|
||||||
|
TOK_INT = 0x0010u,
|
||||||
|
TOK_STRING = 0x0020u,
|
||||||
|
__TOK_UBOUND = 0x0040u,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum token_value_type {
|
||||||
|
TOK_V_NONE = 0,
|
||||||
|
TOK_V_INT,
|
||||||
|
TOK_V_STRING,
|
||||||
|
TOK_V_SYMBOL,
|
||||||
|
TOK_V_KEYWORD,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum token_symbol {
|
||||||
|
SYM_NONE = 0,
|
||||||
|
SYM_COMMA = __TOK_UBOUND,
|
||||||
|
SYM_HYPHEN,
|
||||||
|
SYM_SEMICOLON,
|
||||||
|
SYM_LEFT_BRACE,
|
||||||
|
SYM_RIGHT_BRACE,
|
||||||
|
SYM_LEFT_PAREN,
|
||||||
|
SYM_RIGHT_PAREN,
|
||||||
|
SYM_HYPHEN_RIGHT_ANGLE,
|
||||||
|
__SYM_UBOUND,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum token_keyword {
|
||||||
|
KW_NONE = 0,
|
||||||
|
KW_INTERFACE = __SYM_UBOUND,
|
||||||
|
KW_MSG,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct token {
|
||||||
|
struct file_span tok_location;
|
||||||
|
enum token_type tok_type;
|
||||||
|
enum token_value_type tok_value_type;
|
||||||
|
b_queue_entry tok_entry;
|
||||||
|
|
||||||
|
union {
|
||||||
|
char *tok_str;
|
||||||
|
enum token_symbol tok_sym;
|
||||||
|
enum token_keyword tok_kw;
|
||||||
|
long long tok_int;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void token_destroy(struct token *tok);
|
||||||
|
extern const char *token_type_to_string(enum token_type type);
|
||||||
|
extern const char *token_symbol_to_string(enum token_symbol sym);
|
||||||
|
extern const char *token_keyword_to_string(enum token_keyword kw);
|
||||||
|
|
||||||
|
#endif
|
||||||
17
toolchain/ifc/type.c
Normal file
17
toolchain/ifc/type.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include "type.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void type_print(const struct type *ty)
|
||||||
|
{
|
||||||
|
switch (ty->ty_id) {
|
||||||
|
case TYPE_INT:
|
||||||
|
printf("int");
|
||||||
|
break;
|
||||||
|
case TYPE_STRING:
|
||||||
|
printf("string");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
toolchain/ifc/type.h
Normal file
17
toolchain/ifc/type.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef IFC_TYPE_H_
|
||||||
|
#define IFC_TYPE_H_
|
||||||
|
|
||||||
|
enum type_id {
|
||||||
|
TYPE_NONE,
|
||||||
|
TYPE_INT,
|
||||||
|
TYPE_STRING,
|
||||||
|
TYPE_OTHER,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type {
|
||||||
|
enum type_id ty_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void type_print(const struct type *ty);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user