Compare commits
2 Commits
master
...
feature/pa
| Author | SHA1 | Date |
|---|---|---|
|
|
03970871db | |
|
|
9a013c53d4 |
|
|
@ -0,0 +1,22 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
project(saqut VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_compile_options(-Wall -Wextra)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR NOT CMAKE_BUILD_TYPE)
|
||||
add_compile_options(-g -O0)
|
||||
message(STATUS "Debug modu aktif")
|
||||
else()
|
||||
add_compile_options(-O3)
|
||||
message(STATUS "Release modu aktif")
|
||||
endif()
|
||||
|
||||
# Tüm kaynak dosyaları topla
|
||||
file(GLOB_RECURSE SOURCES "src/*.cpp")
|
||||
|
||||
add_executable(saqut ${SOURCES})
|
||||
|
||||
target_include_directories(saqut PRIVATE src)
|
||||
Binary file not shown.
|
|
@ -0,0 +1,16 @@
|
|||
# ninja log v7
|
||||
1 1875 1779866878396024286 CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o eb96bb4b1eb4ad80
|
||||
1 1743 1779866878396133191 CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o 78f2c4da7c9b2281
|
||||
1 1835 1779866851291850429 CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o d2e2bb2f8a63c6d2
|
||||
3 1976 1779866851293202930 CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o ac5bbcd74d87561a
|
||||
1 1828 1779866851291959426 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o b6c56f04a257f685
|
||||
1 1991 1779866851292085983 CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o 4057e3d63c63a1ab
|
||||
6 2108 1779866851296202934 CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o b5c20724bbf3648c
|
||||
1 2478 1779866878395241768 CMakeFiles/saqut.dir/src/main.cpp.o 110c26cb1d0c3a23
|
||||
2967 3100 1779866359829193015 saqut 78d8bacf305cfc59
|
||||
1 1450 1779866851291202927 CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o 90eeec811f2137e6
|
||||
0 1481 1779866851290202926 CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o da6f5fc90e87e6b1
|
||||
1 1410 1779866878396365249 CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o a01677f8bb4f4dbc
|
||||
1 1579 1779866878396233551 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 2c65b7be26cead32
|
||||
1 1163 1779866916763301383 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 2c65b7be26cead32
|
||||
1163 1283 1779866917925303269 saqut 89052e51305cb697
|
||||
|
|
@ -0,0 +1,360 @@
|
|||
# This is the CMakeCache file.
|
||||
# For build in directory: /home/saqut/Masaüstü/saqutcompiler/build
|
||||
# It was generated by CMake: /usr/bin/cmake
|
||||
# You can edit this file to change values found and used by cmake.
|
||||
# If you do not want to change any of the values, simply exit the editor.
|
||||
# If you do want to change a value, simply edit, save, and exit the editor.
|
||||
# The syntax for the file is as follows:
|
||||
# KEY:TYPE=VALUE
|
||||
# KEY is the name of a variable in the cache.
|
||||
# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!.
|
||||
# VALUE is the current value for the KEY.
|
||||
|
||||
########################
|
||||
# EXTERNAL cache entries
|
||||
########################
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_ADDR2LINE:FILEPATH=/usr/bin/addr2line
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_AR:FILEPATH=/usr/bin/ar
|
||||
|
||||
//Choose the type of build, options are: None Debug Release RelWithDebInfo
|
||||
// MinSizeRel ...
|
||||
CMAKE_BUILD_TYPE:STRING=Debug
|
||||
|
||||
//CXX compiler
|
||||
CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++
|
||||
|
||||
//A wrapper around 'ar' adding the appropriate '--plugin' option
|
||||
// for the GCC compiler
|
||||
CMAKE_CXX_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar
|
||||
|
||||
//A wrapper around 'ranlib' adding the appropriate '--plugin' option
|
||||
// for the GCC compiler
|
||||
CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib
|
||||
|
||||
//Flags used by the CXX compiler during all build types.
|
||||
CMAKE_CXX_FLAGS:STRING=
|
||||
|
||||
//Flags used by the CXX compiler during DEBUG builds.
|
||||
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
|
||||
|
||||
//Flags used by the CXX compiler during MINSIZEREL builds.
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
|
||||
|
||||
//Flags used by the CXX compiler during RELEASE builds.
|
||||
CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
|
||||
|
||||
//Flags used by the CXX compiler during RELWITHDEBINFO builds.
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_DLLTOOL:FILEPATH=CMAKE_DLLTOOL-NOTFOUND
|
||||
|
||||
//Flags used by the linker during all build types.
|
||||
CMAKE_EXE_LINKER_FLAGS:STRING=
|
||||
|
||||
//Flags used by the linker during DEBUG builds.
|
||||
CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=
|
||||
|
||||
//Flags used by the linker during MINSIZEREL builds.
|
||||
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||
|
||||
//Flags used by the linker during RELEASE builds.
|
||||
CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=
|
||||
|
||||
//Flags used by the linker during RELWITHDEBINFO builds.
|
||||
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||
|
||||
//Enable/Disable output of build database during the build.
|
||||
CMAKE_EXPORT_BUILD_DATABASE:BOOL=
|
||||
|
||||
//Enable/Disable output of compile commands during generation.
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=
|
||||
|
||||
//Value Computed by CMake.
|
||||
CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/pkgRedirects
|
||||
|
||||
//Install path prefix, prepended onto install directories.
|
||||
CMAKE_INSTALL_PREFIX:PATH=/usr/local
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_LINKER:FILEPATH=/usr/bin/ld
|
||||
|
||||
//Program used to build from build.ninja files.
|
||||
CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/ninja
|
||||
|
||||
//Flags used by the linker during the creation of modules during
|
||||
// all build types.
|
||||
CMAKE_MODULE_LINKER_FLAGS:STRING=
|
||||
|
||||
//Flags used by the linker during the creation of modules during
|
||||
// DEBUG builds.
|
||||
CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=
|
||||
|
||||
//Flags used by the linker during the creation of modules during
|
||||
// MINSIZEREL builds.
|
||||
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||
|
||||
//Flags used by the linker during the creation of modules during
|
||||
// RELEASE builds.
|
||||
CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=
|
||||
|
||||
//Flags used by the linker during the creation of modules during
|
||||
// RELWITHDEBINFO builds.
|
||||
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_NM:FILEPATH=/usr/bin/nm
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_COMPAT_VERSION:STATIC=
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_DESCRIPTION:STATIC=
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_HOMEPAGE_URL:STATIC=
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_NAME:STATIC=saqut
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_SPDX_LICENSE:STATIC=
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_VERSION:STATIC=0.1
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_VERSION_MAJOR:STATIC=0
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_VERSION_MINOR:STATIC=1
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_VERSION_PATCH:STATIC=
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_VERSION_TWEAK:STATIC=
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_READELF:FILEPATH=/usr/bin/readelf
|
||||
|
||||
//Flags used by the linker during the creation of shared libraries
|
||||
// during all build types.
|
||||
CMAKE_SHARED_LINKER_FLAGS:STRING=
|
||||
|
||||
//Flags used by the linker during the creation of shared libraries
|
||||
// during DEBUG builds.
|
||||
CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=
|
||||
|
||||
//Flags used by the linker during the creation of shared libraries
|
||||
// during MINSIZEREL builds.
|
||||
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||
|
||||
//Flags used by the linker during the creation of shared libraries
|
||||
// during RELEASE builds.
|
||||
CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=
|
||||
|
||||
//Flags used by the linker during the creation of shared libraries
|
||||
// during RELWITHDEBINFO builds.
|
||||
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||
|
||||
//If set, runtime paths are not added when installing shared libraries,
|
||||
// but are added when building.
|
||||
CMAKE_SKIP_INSTALL_RPATH:BOOL=NO
|
||||
|
||||
//If set, runtime paths are not added when using shared libraries.
|
||||
CMAKE_SKIP_RPATH:BOOL=NO
|
||||
|
||||
//Flags used by the archiver during the creation of static libraries
|
||||
// during all build types.
|
||||
CMAKE_STATIC_LINKER_FLAGS:STRING=
|
||||
|
||||
//Flags used by the archiver during the creation of static libraries
|
||||
// during DEBUG builds.
|
||||
CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING=
|
||||
|
||||
//Flags used by the archiver during the creation of static libraries
|
||||
// during MINSIZEREL builds.
|
||||
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||
|
||||
//Flags used by the archiver during the creation of static libraries
|
||||
// during RELEASE builds.
|
||||
CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING=
|
||||
|
||||
//Flags used by the archiver during the creation of static libraries
|
||||
// during RELWITHDEBINFO builds.
|
||||
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_STRIP:FILEPATH=/usr/bin/strip
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_TAPI:FILEPATH=CMAKE_TAPI-NOTFOUND
|
||||
|
||||
//If this value is on, makefiles will be generated without the
|
||||
// .SILENT directive, and all commands will be echoed to the console
|
||||
// during the make. This is useful for debugging only. With Visual
|
||||
// Studio IDE projects all commands are done without /nologo.
|
||||
CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE
|
||||
|
||||
//Value Computed by CMake
|
||||
saqut_BINARY_DIR:STATIC=/home/saqut/Masaüstü/saqutcompiler/build
|
||||
|
||||
//Value Computed by CMake
|
||||
saqut_IS_TOP_LEVEL:STATIC=ON
|
||||
|
||||
//Value Computed by CMake
|
||||
saqut_SOURCE_DIR:STATIC=/home/saqut/Masaüstü/saqutcompiler
|
||||
|
||||
|
||||
########################
|
||||
# INTERNAL cache entries
|
||||
########################
|
||||
|
||||
//ADVANCED property for variable: CMAKE_ADDR2LINE
|
||||
CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_AR
|
||||
CMAKE_AR-ADVANCED:INTERNAL=1
|
||||
//This is the directory where this CMakeCache.txt was created
|
||||
CMAKE_CACHEFILE_DIR:INTERNAL=/home/saqut/Masaüstü/saqutcompiler/build
|
||||
//Major version of cmake used to create the current loaded cache
|
||||
CMAKE_CACHE_MAJOR_VERSION:INTERNAL=4
|
||||
//Minor version of cmake used to create the current loaded cache
|
||||
CMAKE_CACHE_MINOR_VERSION:INTERNAL=3
|
||||
//Patch version of cmake used to create the current loaded cache
|
||||
CMAKE_CACHE_PATCH_VERSION:INTERNAL=2
|
||||
//Path to CMake executable.
|
||||
CMAKE_COMMAND:INTERNAL=/usr/bin/cmake
|
||||
//Path to cpack program executable.
|
||||
CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack
|
||||
//Path to ctest program executable.
|
||||
CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest
|
||||
//ADVANCED property for variable: CMAKE_CXX_COMPILER
|
||||
CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR
|
||||
CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB
|
||||
CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS
|
||||
CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG
|
||||
CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_DLLTOOL
|
||||
CMAKE_DLLTOOL-ADVANCED:INTERNAL=1
|
||||
//Path to cache edit program executable.
|
||||
CMAKE_EDIT_COMMAND:INTERNAL=/usr/bin/ccmake
|
||||
//Executable file format
|
||||
CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
|
||||
CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG
|
||||
CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL
|
||||
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE
|
||||
CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXPORT_BUILD_DATABASE
|
||||
CMAKE_EXPORT_BUILD_DATABASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1
|
||||
//Name of external makefile project generator.
|
||||
CMAKE_EXTRA_GENERATOR:INTERNAL=
|
||||
//Name of generator.
|
||||
CMAKE_GENERATOR:INTERNAL=Ninja
|
||||
//Generator instance identifier.
|
||||
CMAKE_GENERATOR_INSTANCE:INTERNAL=
|
||||
//Name of generator platform.
|
||||
CMAKE_GENERATOR_PLATFORM:INTERNAL=
|
||||
//Name of generator toolset.
|
||||
CMAKE_GENERATOR_TOOLSET:INTERNAL=
|
||||
//Source directory with the top level CMakeLists.txt file for this
|
||||
// project
|
||||
CMAKE_HOME_DIRECTORY:INTERNAL=/home/saqut/Masaüstü/saqutcompiler
|
||||
//Install .so files without execute permission.
|
||||
CMAKE_INSTALL_SO_NO_EXE:INTERNAL=0
|
||||
//ADVANCED property for variable: CMAKE_LINKER
|
||||
CMAKE_LINKER-ADVANCED:INTERNAL=1
|
||||
//Name of CMakeLists files to read
|
||||
CMAKE_LIST_FILE_NAME:INTERNAL=CMakeLists.txt
|
||||
//ADVANCED property for variable: CMAKE_MAKE_PROGRAM
|
||||
CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS
|
||||
CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG
|
||||
CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL
|
||||
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE
|
||||
CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_NM
|
||||
CMAKE_NM-ADVANCED:INTERNAL=1
|
||||
//number of local generators
|
||||
CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_OBJCOPY
|
||||
CMAKE_OBJCOPY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_OBJDUMP
|
||||
CMAKE_OBJDUMP-ADVANCED:INTERNAL=1
|
||||
//Platform information initialized
|
||||
CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_RANLIB
|
||||
CMAKE_RANLIB-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_READELF
|
||||
CMAKE_READELF-ADVANCED:INTERNAL=1
|
||||
//Path to CMake installation.
|
||||
CMAKE_ROOT:INTERNAL=/usr/share/cmake
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS
|
||||
CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG
|
||||
CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
|
||||
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE
|
||||
CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH
|
||||
CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SKIP_RPATH
|
||||
CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS
|
||||
CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG
|
||||
CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL
|
||||
CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE
|
||||
CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_STRIP
|
||||
CMAKE_STRIP-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_TAPI
|
||||
CMAKE_TAPI-ADVANCED:INTERNAL=1
|
||||
//uname command
|
||||
CMAKE_UNAME:INTERNAL=/usr/bin/uname
|
||||
//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
|
||||
CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
|
||||
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
set(CMAKE_CXX_COMPILER "/usr/bin/c++")
|
||||
set(CMAKE_CXX_COMPILER_ARG1 "")
|
||||
set(CMAKE_CXX_COMPILER_ID "GNU")
|
||||
set(CMAKE_CXX_COMPILER_VERSION "16.1.1")
|
||||
set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "")
|
||||
set(CMAKE_CXX_COMPILER_WRAPPER "")
|
||||
set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "20")
|
||||
set(CMAKE_CXX_EXTENSIONS_COMPUTED_DEFAULT "ON")
|
||||
set(CMAKE_CXX_STANDARD_LATEST "26")
|
||||
set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20;cxx_std_23;cxx_std_26")
|
||||
set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters")
|
||||
set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates")
|
||||
set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates")
|
||||
set(CMAKE_CXX17_COMPILE_FEATURES "cxx_std_17")
|
||||
set(CMAKE_CXX20_COMPILE_FEATURES "cxx_std_20")
|
||||
set(CMAKE_CXX23_COMPILE_FEATURES "cxx_std_23")
|
||||
set(CMAKE_CXX26_COMPILE_FEATURES "cxx_std_26")
|
||||
|
||||
set(CMAKE_CXX_PLATFORM_ID "Linux")
|
||||
set(CMAKE_CXX_SIMULATE_ID "")
|
||||
set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "GNU")
|
||||
set(CMAKE_CXX_COMPILER_APPLE_SYSROOT "")
|
||||
set(CMAKE_CXX_SIMULATE_VERSION "")
|
||||
set(CMAKE_CXX_COMPILER_ARCHITECTURE_ID "x86_64")
|
||||
|
||||
|
||||
|
||||
|
||||
set(CMAKE_AR "/usr/bin/ar")
|
||||
set(CMAKE_CXX_COMPILER_AR "/usr/bin/gcc-ar")
|
||||
set(CMAKE_RANLIB "/usr/bin/ranlib")
|
||||
set(CMAKE_CXX_COMPILER_RANLIB "/usr/bin/gcc-ranlib")
|
||||
set(CMAKE_LINKER "/usr/bin/ld")
|
||||
set(CMAKE_LINKER_LINK "")
|
||||
set(CMAKE_LINKER_LLD "")
|
||||
set(CMAKE_CXX_COMPILER_LINKER "/usr/bin/ld")
|
||||
set(CMAKE_CXX_COMPILER_LINKER_ID "GNU")
|
||||
set(CMAKE_CXX_COMPILER_LINKER_VERSION 2.46.0)
|
||||
set(CMAKE_CXX_COMPILER_LINKER_FRONTEND_VARIANT GNU)
|
||||
set(CMAKE_MT "")
|
||||
set(CMAKE_TAPI "CMAKE_TAPI-NOTFOUND")
|
||||
set(CMAKE_COMPILER_IS_GNUCXX 1)
|
||||
set(CMAKE_CXX_COMPILER_LOADED 1)
|
||||
set(CMAKE_CXX_COMPILER_WORKS TRUE)
|
||||
set(CMAKE_CXX_ABI_COMPILED TRUE)
|
||||
|
||||
set(CMAKE_CXX_COMPILER_ENV_VAR "CXX")
|
||||
|
||||
set(CMAKE_CXX_COMPILER_ID_RUN 1)
|
||||
set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm;ccm;cxxm;c++m)
|
||||
set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
|
||||
|
||||
foreach (lang IN ITEMS C OBJC OBJCXX)
|
||||
if (CMAKE_${lang}_COMPILER_ID_RUN)
|
||||
foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS)
|
||||
list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension})
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(CMAKE_CXX_LINKER_PREFERENCE 30)
|
||||
set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1)
|
||||
set(CMAKE_CXX_LINKER_DEPFILE_SUPPORTED TRUE)
|
||||
set(CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED TRUE)
|
||||
set(CMAKE_CXX_LINKER_PUSHPOP_STATE_SUPPORTED TRUE)
|
||||
|
||||
# Save compiler ABI information.
|
||||
set(CMAKE_CXX_SIZEOF_DATA_PTR "8")
|
||||
set(CMAKE_CXX_COMPILER_ABI "ELF")
|
||||
set(CMAKE_CXX_BYTE_ORDER "LITTLE_ENDIAN")
|
||||
set(CMAKE_CXX_LIBRARY_ARCHITECTURE "")
|
||||
|
||||
if(CMAKE_CXX_SIZEOF_DATA_PTR)
|
||||
set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ABI)
|
||||
set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_LIBRARY_ARCHITECTURE)
|
||||
set(CMAKE_LIBRARY_ARCHITECTURE "")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "")
|
||||
if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX)
|
||||
set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}")
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "/usr/include/c++/16.1.1;/usr/include/c++/16.1.1/x86_64-pc-linux-gnu;/usr/include/c++/16.1.1/backward;/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/include;/usr/local/include;/usr/include")
|
||||
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "stdc++;m;gcc_s;gcc;atomic_asneeded;c;gcc_s;gcc")
|
||||
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1;/usr/lib;/lib")
|
||||
set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
|
||||
set(CMAKE_CXX_COMPILER_CLANG_RESOURCE_DIR "")
|
||||
|
||||
set(CMAKE_CXX_COMPILER_IMPORT_STD "")
|
||||
set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled (usually a `project()` call)")
|
||||
set(CMAKE_CXX_STDLIB_MODULES_JSON "")
|
||||
Binary file not shown.
|
|
@ -0,0 +1,15 @@
|
|||
set(CMAKE_HOST_SYSTEM "Linux-7.0.9-1-MANJARO")
|
||||
set(CMAKE_HOST_SYSTEM_NAME "Linux")
|
||||
set(CMAKE_HOST_SYSTEM_VERSION "7.0.9-1-MANJARO")
|
||||
set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64")
|
||||
|
||||
|
||||
|
||||
set(CMAKE_SYSTEM "Linux-7.0.9-1-MANJARO")
|
||||
set(CMAKE_SYSTEM_NAME "Linux")
|
||||
set(CMAKE_SYSTEM_VERSION "7.0.9-1-MANJARO")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "x86_64")
|
||||
|
||||
set(CMAKE_CROSSCOMPILING "FALSE")
|
||||
|
||||
set(CMAKE_SYSTEM_LOADED 1)
|
||||
|
|
@ -0,0 +1,949 @@
|
|||
/* This source file must have a .cpp extension so that all C++ compilers
|
||||
recognize the extension without flags. Borland does not know .cxx for
|
||||
example. */
|
||||
#ifndef __cplusplus
|
||||
# error "A C compiler has been selected for C++."
|
||||
#endif
|
||||
|
||||
#if !defined(__has_include)
|
||||
/* If the compiler does not have __has_include, pretend the answer is
|
||||
always no. */
|
||||
# define __has_include(x) 0
|
||||
#endif
|
||||
|
||||
|
||||
/* Version number components: V=Version, R=Revision, P=Patch
|
||||
Version date components: YYYY=Year, MM=Month, DD=Day */
|
||||
|
||||
#if defined(__INTEL_COMPILER) || defined(__ICC)
|
||||
# define COMPILER_ID "Intel"
|
||||
# if defined(_MSC_VER)
|
||||
# define SIMULATE_ID "MSVC"
|
||||
# endif
|
||||
# if defined(__GNUC__)
|
||||
# define SIMULATE_ID "GNU"
|
||||
# endif
|
||||
/* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later,
|
||||
except that a few beta releases use the old format with V=2021. */
|
||||
# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111
|
||||
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
|
||||
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
|
||||
# if defined(__INTEL_COMPILER_UPDATE)
|
||||
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)
|
||||
# else
|
||||
# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10)
|
||||
# endif
|
||||
# else
|
||||
# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER)
|
||||
# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE)
|
||||
/* The third version component from --version is an update index,
|
||||
but no macro is provided for it. */
|
||||
# define COMPILER_VERSION_PATCH DEC(0)
|
||||
# endif
|
||||
# if defined(__INTEL_COMPILER_BUILD_DATE)
|
||||
/* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */
|
||||
# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)
|
||||
# endif
|
||||
# if defined(_MSC_VER)
|
||||
/* _MSC_VER = VVRR */
|
||||
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||
# endif
|
||||
# if defined(__GNUC__)
|
||||
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
|
||||
# elif defined(__GNUG__)
|
||||
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
|
||||
# endif
|
||||
# if defined(__GNUC_MINOR__)
|
||||
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||
# endif
|
||||
# if defined(__GNUC_PATCHLEVEL__)
|
||||
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||
# endif
|
||||
|
||||
#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)
|
||||
# define COMPILER_ID "IntelLLVM"
|
||||
#if defined(_MSC_VER)
|
||||
# define SIMULATE_ID "MSVC"
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
# define SIMULATE_ID "GNU"
|
||||
#endif
|
||||
/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
|
||||
* later. Look for 6 digit vs. 8 digit version number to decide encoding.
|
||||
* VVVV is no smaller than the current year when a version is released.
|
||||
*/
|
||||
#if __INTEL_LLVM_COMPILER < 1000000L
|
||||
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)
|
||||
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)
|
||||
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 10)
|
||||
#else
|
||||
# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)
|
||||
# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)
|
||||
# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 100)
|
||||
#endif
|
||||
#if defined(_MSC_VER)
|
||||
/* _MSC_VER = VVRR */
|
||||
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
|
||||
#elif defined(__GNUG__)
|
||||
# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)
|
||||
#endif
|
||||
#if defined(__GNUC_MINOR__)
|
||||
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||
#endif
|
||||
#if defined(__GNUC_PATCHLEVEL__)
|
||||
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
#elif defined(__PATHCC__)
|
||||
# define COMPILER_ID "PathScale"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)
|
||||
# if defined(__PATHCC_PATCHLEVEL__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)
|
||||
# endif
|
||||
|
||||
#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)
|
||||
# define COMPILER_ID "Embarcadero"
|
||||
# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)
|
||||
# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)
|
||||
# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF)
|
||||
|
||||
#elif defined(__BORLANDC__)
|
||||
# define COMPILER_ID "Borland"
|
||||
/* __BORLANDC__ = 0xVRR */
|
||||
# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)
|
||||
# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)
|
||||
|
||||
#elif defined(__WATCOMC__) && __WATCOMC__ < 1200
|
||||
# define COMPILER_ID "Watcom"
|
||||
/* __WATCOMC__ = VVRR */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)
|
||||
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
|
||||
# if (__WATCOMC__ % 10) > 0
|
||||
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
|
||||
# endif
|
||||
|
||||
#elif defined(__WATCOMC__)
|
||||
# define COMPILER_ID "OpenWatcom"
|
||||
/* __WATCOMC__ = VVRP + 1100 */
|
||||
# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)
|
||||
# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)
|
||||
# if (__WATCOMC__ % 10) > 0
|
||||
# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)
|
||||
# endif
|
||||
|
||||
#elif defined(__SUNPRO_CC)
|
||||
# define COMPILER_ID "SunPro"
|
||||
# if __SUNPRO_CC >= 0x5100
|
||||
/* __SUNPRO_CC = 0xVRRP */
|
||||
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12)
|
||||
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF)
|
||||
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF)
|
||||
# else
|
||||
/* __SUNPRO_CC = 0xVRP */
|
||||
# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8)
|
||||
# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF)
|
||||
# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF)
|
||||
# endif
|
||||
|
||||
#elif defined(__HP_aCC)
|
||||
# define COMPILER_ID "HP"
|
||||
/* __HP_aCC = VVRRPP */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000)
|
||||
# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100)
|
||||
# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100)
|
||||
|
||||
#elif defined(__DECCXX)
|
||||
# define COMPILER_ID "Compaq"
|
||||
/* __DECCXX_VER = VVRRTPPPP */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000)
|
||||
# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100)
|
||||
# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000)
|
||||
|
||||
#elif defined(__IBMCPP__) && defined(__COMPILER_VER__)
|
||||
# define COMPILER_ID "zOS"
|
||||
/* __IBMCPP__ = VRP */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
|
||||
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
|
||||
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10)
|
||||
|
||||
#elif defined(__open_xl__) && defined(__clang__)
|
||||
# define COMPILER_ID "IBMClang"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__open_xl_version__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__open_xl_release__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__open_xl_modification__)
|
||||
# define COMPILER_VERSION_TWEAK DEC(__open_xl_ptf_fix_level__)
|
||||
# define COMPILER_VERSION_INTERNAL_STR __clang_version__
|
||||
|
||||
|
||||
#elif defined(__ibmxl__) && defined(__clang__)
|
||||
# define COMPILER_ID "XLClang"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)
|
||||
# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)
|
||||
|
||||
|
||||
#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800
|
||||
# define COMPILER_ID "XL"
|
||||
/* __IBMCPP__ = VRP */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
|
||||
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
|
||||
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10)
|
||||
|
||||
#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800
|
||||
# define COMPILER_ID "VisualAge"
|
||||
/* __IBMCPP__ = VRP */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)
|
||||
# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)
|
||||
# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10)
|
||||
|
||||
#elif defined(__NVCOMPILER)
|
||||
# define COMPILER_ID "NVHPC"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)
|
||||
# if defined(__NVCOMPILER_PATCHLEVEL__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)
|
||||
# endif
|
||||
|
||||
#elif defined(__PGI)
|
||||
# define COMPILER_ID "PGI"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__PGIC__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
|
||||
# if defined(__PGIC_PATCHLEVEL__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
|
||||
# endif
|
||||
|
||||
#elif defined(__clang__) && defined(__cray__)
|
||||
# define COMPILER_ID "CrayClang"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__cray_major__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__cray_minor__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__cray_patchlevel__)
|
||||
# define COMPILER_VERSION_INTERNAL_STR __clang_version__
|
||||
|
||||
|
||||
#elif defined(_CRAYC)
|
||||
# define COMPILER_ID "Cray"
|
||||
# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)
|
||||
# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)
|
||||
|
||||
#elif defined(__TI_COMPILER_VERSION__)
|
||||
# define COMPILER_ID "TI"
|
||||
/* __TI_COMPILER_VERSION__ = VVVRRRPPP */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)
|
||||
# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000)
|
||||
# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000)
|
||||
|
||||
#elif defined(__CLANG_FUJITSU)
|
||||
# define COMPILER_ID "FujitsuClang"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
|
||||
# define COMPILER_VERSION_INTERNAL_STR __clang_version__
|
||||
|
||||
|
||||
#elif defined(__FUJITSU)
|
||||
# define COMPILER_ID "Fujitsu"
|
||||
# if defined(__FCC_version__)
|
||||
# define COMPILER_VERSION __FCC_version__
|
||||
# elif defined(__FCC_major__)
|
||||
# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)
|
||||
# endif
|
||||
# if defined(__fcc_version)
|
||||
# define COMPILER_VERSION_INTERNAL DEC(__fcc_version)
|
||||
# elif defined(__FCC_VERSION)
|
||||
# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION)
|
||||
# endif
|
||||
|
||||
|
||||
#elif defined(__ghs__)
|
||||
# define COMPILER_ID "GHS"
|
||||
/* __GHS_VERSION_NUMBER = VVVVRP */
|
||||
# ifdef __GHS_VERSION_NUMBER
|
||||
# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)
|
||||
# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)
|
||||
# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10)
|
||||
# endif
|
||||
|
||||
#elif defined(__TASKING__)
|
||||
# define COMPILER_ID "Tasking"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__VERSION__/1000)
|
||||
# define COMPILER_VERSION_MINOR DEC(__VERSION__ % 100)
|
||||
# define COMPILER_VERSION_INTERNAL DEC(__VERSION__)
|
||||
|
||||
#elif defined(__ORANGEC__)
|
||||
# define COMPILER_ID "OrangeC"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__ORANGEC_MAJOR__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__ORANGEC_MINOR__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__ORANGEC_PATCHLEVEL__)
|
||||
|
||||
#elif defined(__RENESAS__)
|
||||
# define COMPILER_ID "Renesas"
|
||||
/* __RENESAS_VERSION__ = 0xVVRRPP00 */
|
||||
# define COMPILER_VERSION_MAJOR HEX(__RENESAS_VERSION__ >> 24 & 0xFF)
|
||||
# define COMPILER_VERSION_MINOR HEX(__RENESAS_VERSION__ >> 16 & 0xFF)
|
||||
# define COMPILER_VERSION_PATCH HEX(__RENESAS_VERSION__ >> 8 & 0xFF)
|
||||
|
||||
#elif defined(__SCO_VERSION__)
|
||||
# define COMPILER_ID "SCO"
|
||||
|
||||
#elif defined(__ARMCC_VERSION) && !defined(__clang__)
|
||||
# define COMPILER_ID "ARMCC"
|
||||
#if __ARMCC_VERSION >= 1000000
|
||||
/* __ARMCC_VERSION = VRRPPPP */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)
|
||||
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)
|
||||
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
|
||||
#else
|
||||
/* __ARMCC_VERSION = VRPPPP */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)
|
||||
# define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)
|
||||
# define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000)
|
||||
#endif
|
||||
|
||||
|
||||
#elif defined(__clang__) && defined(__apple_build_version__)
|
||||
# define COMPILER_ID "AppleClang"
|
||||
# if defined(_MSC_VER)
|
||||
# define SIMULATE_ID "MSVC"
|
||||
# endif
|
||||
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
|
||||
# if defined(_MSC_VER)
|
||||
/* _MSC_VER = VVRR */
|
||||
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||
# endif
|
||||
# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)
|
||||
|
||||
#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION)
|
||||
# define COMPILER_ID "ARMClang"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)
|
||||
# define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)
|
||||
# define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION/100 % 100)
|
||||
# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)
|
||||
|
||||
#elif defined(__clang__) && defined(__ti__)
|
||||
# define COMPILER_ID "TIClang"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__ti_major__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__ti_minor__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__ti_patchlevel__)
|
||||
# define COMPILER_VERSION_INTERNAL DEC(__ti_version__)
|
||||
|
||||
#elif defined(__clang__)
|
||||
# define COMPILER_ID "Clang"
|
||||
# if defined(_MSC_VER)
|
||||
# define SIMULATE_ID "MSVC"
|
||||
# endif
|
||||
# define COMPILER_VERSION_MAJOR DEC(__clang_major__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__clang_minor__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)
|
||||
# if defined(_MSC_VER)
|
||||
/* _MSC_VER = VVRR */
|
||||
# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||
# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||
# endif
|
||||
|
||||
#elif defined(__LCC__) && (defined(__GNUC__) || defined(__GNUG__) || defined(__MCST__))
|
||||
# define COMPILER_ID "LCC"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__LCC__ / 100)
|
||||
# define COMPILER_VERSION_MINOR DEC(__LCC__ % 100)
|
||||
# if defined(__LCC_MINOR__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__LCC_MINOR__)
|
||||
# endif
|
||||
# if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
# define SIMULATE_ID "GNU"
|
||||
# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)
|
||||
# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||
# if defined(__GNUC_PATCHLEVEL__)
|
||||
# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
# define COMPILER_ID "GNU"
|
||||
# if defined(__GNUC__)
|
||||
# define COMPILER_VERSION_MAJOR DEC(__GNUC__)
|
||||
# else
|
||||
# define COMPILER_VERSION_MAJOR DEC(__GNUG__)
|
||||
# endif
|
||||
# if defined(__GNUC_MINOR__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)
|
||||
# endif
|
||||
# if defined(__GNUC_PATCHLEVEL__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)
|
||||
# endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
# define COMPILER_ID "MSVC"
|
||||
/* _MSC_VER = VVRR */
|
||||
# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)
|
||||
# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)
|
||||
# if defined(_MSC_FULL_VER)
|
||||
# if _MSC_VER >= 1400
|
||||
/* _MSC_FULL_VER = VVRRPPPPP */
|
||||
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)
|
||||
# else
|
||||
/* _MSC_FULL_VER = VVRRPPPP */
|
||||
# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)
|
||||
# endif
|
||||
# endif
|
||||
# if defined(_MSC_BUILD)
|
||||
# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)
|
||||
# endif
|
||||
|
||||
#elif defined(_ADI_COMPILER)
|
||||
# define COMPILER_ID "ADSP"
|
||||
#if defined(__VERSIONNUM__)
|
||||
/* __VERSIONNUM__ = 0xVVRRPPTT */
|
||||
# define COMPILER_VERSION_MAJOR DEC(__VERSIONNUM__ >> 24 & 0xFF)
|
||||
# define COMPILER_VERSION_MINOR DEC(__VERSIONNUM__ >> 16 & 0xFF)
|
||||
# define COMPILER_VERSION_PATCH DEC(__VERSIONNUM__ >> 8 & 0xFF)
|
||||
# define COMPILER_VERSION_TWEAK DEC(__VERSIONNUM__ & 0xFF)
|
||||
#endif
|
||||
|
||||
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
|
||||
# define COMPILER_ID "IAR"
|
||||
# if defined(__VER__) && defined(__ICCARM__)
|
||||
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)
|
||||
# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)
|
||||
# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)
|
||||
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
|
||||
# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))
|
||||
# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)
|
||||
# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))
|
||||
# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)
|
||||
# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)
|
||||
# endif
|
||||
|
||||
#elif defined(__DCC__) && defined(_DIAB_TOOL)
|
||||
# define COMPILER_ID "Diab"
|
||||
# define COMPILER_VERSION_MAJOR DEC(__VERSION_MAJOR_NUMBER__)
|
||||
# define COMPILER_VERSION_MINOR DEC(__VERSION_MINOR_NUMBER__)
|
||||
# define COMPILER_VERSION_PATCH DEC(__VERSION_ARCH_FEATURE_NUMBER__)
|
||||
# define COMPILER_VERSION_TWEAK DEC(__VERSION_BUG_FIX_NUMBER__)
|
||||
|
||||
|
||||
|
||||
/* These compilers are either not known or too old to define an
|
||||
identification macro. Try to identify the platform and guess that
|
||||
it is the native compiler. */
|
||||
#elif defined(__hpux) || defined(__hpua)
|
||||
# define COMPILER_ID "HP"
|
||||
|
||||
#else /* unknown compiler */
|
||||
# define COMPILER_ID ""
|
||||
#endif
|
||||
|
||||
/* Construct the string literal in pieces to prevent the source from
|
||||
getting matched. Store it in a pointer rather than an array
|
||||
because some compilers will just produce instructions to fill the
|
||||
array rather than assigning a pointer to a static array. */
|
||||
char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";
|
||||
#ifdef SIMULATE_ID
|
||||
char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
|
||||
#endif
|
||||
|
||||
#ifdef __QNXNTO__
|
||||
char const* qnxnto = "INFO" ":" "qnxnto[]";
|
||||
#endif
|
||||
|
||||
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
|
||||
char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
|
||||
#endif
|
||||
|
||||
#define STRINGIFY_HELPER(X) #X
|
||||
#define STRINGIFY(X) STRINGIFY_HELPER(X)
|
||||
|
||||
/* Identify known platforms by name. */
|
||||
#if defined(__linux) || defined(__linux__) || defined(linux)
|
||||
# define PLATFORM_ID "Linux"
|
||||
|
||||
#elif defined(__MSYS__)
|
||||
# define PLATFORM_ID "MSYS"
|
||||
|
||||
#elif defined(__CYGWIN__)
|
||||
# define PLATFORM_ID "Cygwin"
|
||||
|
||||
#elif defined(__MINGW32__)
|
||||
# define PLATFORM_ID "MinGW"
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
# define PLATFORM_ID "Darwin"
|
||||
|
||||
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
# define PLATFORM_ID "Windows"
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD)
|
||||
# define PLATFORM_ID "FreeBSD"
|
||||
|
||||
#elif defined(__NetBSD__) || defined(__NetBSD)
|
||||
# define PLATFORM_ID "NetBSD"
|
||||
|
||||
#elif defined(__OpenBSD__) || defined(__OPENBSD)
|
||||
# define PLATFORM_ID "OpenBSD"
|
||||
|
||||
#elif defined(__sun) || defined(sun)
|
||||
# define PLATFORM_ID "SunOS"
|
||||
|
||||
#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
|
||||
# define PLATFORM_ID "AIX"
|
||||
|
||||
#elif defined(__hpux) || defined(__hpux__)
|
||||
# define PLATFORM_ID "HP-UX"
|
||||
|
||||
#elif defined(__HAIKU__)
|
||||
# define PLATFORM_ID "Haiku"
|
||||
|
||||
#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
|
||||
# define PLATFORM_ID "BeOS"
|
||||
|
||||
#elif defined(__QNX__) || defined(__QNXNTO__)
|
||||
# define PLATFORM_ID "QNX"
|
||||
|
||||
#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
|
||||
# define PLATFORM_ID "Tru64"
|
||||
|
||||
#elif defined(__riscos) || defined(__riscos__)
|
||||
# define PLATFORM_ID "RISCos"
|
||||
|
||||
#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
|
||||
# define PLATFORM_ID "SINIX"
|
||||
|
||||
#elif defined(__UNIX_SV__)
|
||||
# define PLATFORM_ID "UNIX_SV"
|
||||
|
||||
#elif defined(__bsdos__)
|
||||
# define PLATFORM_ID "BSDOS"
|
||||
|
||||
#elif defined(_MPRAS) || defined(MPRAS)
|
||||
# define PLATFORM_ID "MP-RAS"
|
||||
|
||||
#elif defined(__osf) || defined(__osf__)
|
||||
# define PLATFORM_ID "OSF1"
|
||||
|
||||
#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
|
||||
# define PLATFORM_ID "SCO_SV"
|
||||
|
||||
#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
|
||||
# define PLATFORM_ID "ULTRIX"
|
||||
|
||||
#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
|
||||
# define PLATFORM_ID "Xenix"
|
||||
|
||||
#elif defined(__WATCOMC__)
|
||||
# if defined(__LINUX__)
|
||||
# define PLATFORM_ID "Linux"
|
||||
|
||||
# elif defined(__DOS__)
|
||||
# define PLATFORM_ID "DOS"
|
||||
|
||||
# elif defined(__OS2__)
|
||||
# define PLATFORM_ID "OS2"
|
||||
|
||||
# elif defined(__WINDOWS__)
|
||||
# define PLATFORM_ID "Windows3x"
|
||||
|
||||
# elif defined(__VXWORKS__)
|
||||
# define PLATFORM_ID "VxWorks"
|
||||
|
||||
# else /* unknown platform */
|
||||
# define PLATFORM_ID
|
||||
# endif
|
||||
|
||||
#elif defined(__INTEGRITY)
|
||||
# if defined(INT_178B)
|
||||
# define PLATFORM_ID "Integrity178"
|
||||
|
||||
# else /* regular Integrity */
|
||||
# define PLATFORM_ID "Integrity"
|
||||
# endif
|
||||
|
||||
# elif defined(_ADI_COMPILER)
|
||||
# define PLATFORM_ID "ADSP"
|
||||
|
||||
#else /* unknown platform */
|
||||
# define PLATFORM_ID
|
||||
|
||||
#endif
|
||||
|
||||
/* For windows compilers MSVC and Intel we can determine
|
||||
the architecture of the compiler being used. This is because
|
||||
the compilers do not have flags that can change the architecture,
|
||||
but rather depend on which compiler is being used
|
||||
*/
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# if defined(_M_IA64)
|
||||
# define ARCHITECTURE_ID "IA64"
|
||||
|
||||
# elif defined(_M_ARM64EC)
|
||||
# define ARCHITECTURE_ID "ARM64EC"
|
||||
|
||||
# elif defined(_M_X64) || defined(_M_AMD64)
|
||||
# define ARCHITECTURE_ID "x64"
|
||||
|
||||
# elif defined(_M_IX86)
|
||||
# define ARCHITECTURE_ID "X86"
|
||||
|
||||
# elif defined(_M_ARM64)
|
||||
# define ARCHITECTURE_ID "ARM64"
|
||||
|
||||
# elif defined(_M_ARM)
|
||||
# if _M_ARM == 4
|
||||
# define ARCHITECTURE_ID "ARMV4I"
|
||||
# elif _M_ARM == 5
|
||||
# define ARCHITECTURE_ID "ARMV5I"
|
||||
# else
|
||||
# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)
|
||||
# endif
|
||||
|
||||
# elif defined(_M_MIPS)
|
||||
# define ARCHITECTURE_ID "MIPS"
|
||||
|
||||
# elif defined(_M_SH)
|
||||
# define ARCHITECTURE_ID "SHx"
|
||||
|
||||
# else /* unknown architecture */
|
||||
# define ARCHITECTURE_ID ""
|
||||
# endif
|
||||
|
||||
#elif defined(__WATCOMC__)
|
||||
# if defined(_M_I86)
|
||||
# define ARCHITECTURE_ID "I86"
|
||||
|
||||
# elif defined(_M_IX86)
|
||||
# define ARCHITECTURE_ID "X86"
|
||||
|
||||
# else /* unknown architecture */
|
||||
# define ARCHITECTURE_ID ""
|
||||
# endif
|
||||
|
||||
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)
|
||||
# if defined(__ICCARM__)
|
||||
# define ARCHITECTURE_ID "ARM"
|
||||
|
||||
# elif defined(__ICCRX__)
|
||||
# define ARCHITECTURE_ID "RX"
|
||||
|
||||
# elif defined(__ICCRH850__)
|
||||
# define ARCHITECTURE_ID "RH850"
|
||||
|
||||
# elif defined(__ICCRL78__)
|
||||
# define ARCHITECTURE_ID "RL78"
|
||||
|
||||
# elif defined(__ICCRISCV__)
|
||||
# define ARCHITECTURE_ID "RISCV"
|
||||
|
||||
# elif defined(__ICCAVR__)
|
||||
# define ARCHITECTURE_ID "AVR"
|
||||
|
||||
# elif defined(__ICC430__)
|
||||
# define ARCHITECTURE_ID "MSP430"
|
||||
|
||||
# elif defined(__ICCV850__)
|
||||
# define ARCHITECTURE_ID "V850"
|
||||
|
||||
# elif defined(__ICC8051__)
|
||||
# define ARCHITECTURE_ID "8051"
|
||||
|
||||
# elif defined(__ICCSTM8__)
|
||||
# define ARCHITECTURE_ID "STM8"
|
||||
|
||||
# else /* unknown architecture */
|
||||
# define ARCHITECTURE_ID ""
|
||||
# endif
|
||||
|
||||
#elif defined(__ghs__)
|
||||
# if defined(__PPC64__)
|
||||
# define ARCHITECTURE_ID "PPC64"
|
||||
|
||||
# elif defined(__ppc__)
|
||||
# define ARCHITECTURE_ID "PPC"
|
||||
|
||||
# elif defined(__ARM__)
|
||||
# define ARCHITECTURE_ID "ARM"
|
||||
|
||||
# elif defined(__x86_64__)
|
||||
# define ARCHITECTURE_ID "x64"
|
||||
|
||||
# elif defined(__i386__)
|
||||
# define ARCHITECTURE_ID "X86"
|
||||
|
||||
# else /* unknown architecture */
|
||||
# define ARCHITECTURE_ID ""
|
||||
# endif
|
||||
|
||||
#elif defined(__clang__) && defined(__ti__)
|
||||
# if defined(__ARM_ARCH)
|
||||
# define ARCHITECTURE_ID "ARM"
|
||||
|
||||
# else /* unknown architecture */
|
||||
# define ARCHITECTURE_ID ""
|
||||
# endif
|
||||
|
||||
#elif defined(__TI_COMPILER_VERSION__)
|
||||
# if defined(__TI_ARM__)
|
||||
# define ARCHITECTURE_ID "ARM"
|
||||
|
||||
# elif defined(__MSP430__)
|
||||
# define ARCHITECTURE_ID "MSP430"
|
||||
|
||||
# elif defined(__TMS320C28XX__)
|
||||
# define ARCHITECTURE_ID "TMS320C28x"
|
||||
|
||||
# elif defined(__TMS320C6X__) || defined(_TMS320C6X)
|
||||
# define ARCHITECTURE_ID "TMS320C6x"
|
||||
|
||||
# else /* unknown architecture */
|
||||
# define ARCHITECTURE_ID ""
|
||||
# endif
|
||||
|
||||
# elif defined(__ADSPSHARC__)
|
||||
# define ARCHITECTURE_ID "SHARC"
|
||||
|
||||
# elif defined(__ADSPBLACKFIN__)
|
||||
# define ARCHITECTURE_ID "Blackfin"
|
||||
|
||||
#elif defined(__TASKING__)
|
||||
|
||||
# if defined(__CTC__) || defined(__CPTC__)
|
||||
# define ARCHITECTURE_ID "TriCore"
|
||||
|
||||
# elif defined(__CMCS__)
|
||||
# define ARCHITECTURE_ID "MCS"
|
||||
|
||||
# elif defined(__CARM__) || defined(__CPARM__)
|
||||
# define ARCHITECTURE_ID "ARM"
|
||||
|
||||
# elif defined(__CARC__)
|
||||
# define ARCHITECTURE_ID "ARC"
|
||||
|
||||
# elif defined(__C51__)
|
||||
# define ARCHITECTURE_ID "8051"
|
||||
|
||||
# elif defined(__CPCP__)
|
||||
# define ARCHITECTURE_ID "PCP"
|
||||
|
||||
# else
|
||||
# define ARCHITECTURE_ID ""
|
||||
# endif
|
||||
|
||||
#elif defined(__RENESAS__)
|
||||
# if defined(__CCRX__)
|
||||
# define ARCHITECTURE_ID "RX"
|
||||
|
||||
# elif defined(__CCRL__)
|
||||
# define ARCHITECTURE_ID "RL78"
|
||||
|
||||
# elif defined(__CCRH__)
|
||||
# define ARCHITECTURE_ID "RH850"
|
||||
|
||||
# else
|
||||
# define ARCHITECTURE_ID ""
|
||||
# endif
|
||||
|
||||
#else
|
||||
# define ARCHITECTURE_ID
|
||||
#endif
|
||||
|
||||
/* Convert integer to decimal digit literals. */
|
||||
#define DEC(n) \
|
||||
('0' + (((n) / 10000000)%10)), \
|
||||
('0' + (((n) / 1000000)%10)), \
|
||||
('0' + (((n) / 100000)%10)), \
|
||||
('0' + (((n) / 10000)%10)), \
|
||||
('0' + (((n) / 1000)%10)), \
|
||||
('0' + (((n) / 100)%10)), \
|
||||
('0' + (((n) / 10)%10)), \
|
||||
('0' + ((n) % 10))
|
||||
|
||||
/* Convert integer to hex digit literals. */
|
||||
#define HEX(n) \
|
||||
('0' + ((n)>>28 & 0xF)), \
|
||||
('0' + ((n)>>24 & 0xF)), \
|
||||
('0' + ((n)>>20 & 0xF)), \
|
||||
('0' + ((n)>>16 & 0xF)), \
|
||||
('0' + ((n)>>12 & 0xF)), \
|
||||
('0' + ((n)>>8 & 0xF)), \
|
||||
('0' + ((n)>>4 & 0xF)), \
|
||||
('0' + ((n) & 0xF))
|
||||
|
||||
/* Construct a string literal encoding the version number. */
|
||||
#ifdef COMPILER_VERSION
|
||||
char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";
|
||||
|
||||
/* Construct a string literal encoding the version number components. */
|
||||
#elif defined(COMPILER_VERSION_MAJOR)
|
||||
char const info_version[] = {
|
||||
'I', 'N', 'F', 'O', ':',
|
||||
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
|
||||
COMPILER_VERSION_MAJOR,
|
||||
# ifdef COMPILER_VERSION_MINOR
|
||||
'.', COMPILER_VERSION_MINOR,
|
||||
# ifdef COMPILER_VERSION_PATCH
|
||||
'.', COMPILER_VERSION_PATCH,
|
||||
# ifdef COMPILER_VERSION_TWEAK
|
||||
'.', COMPILER_VERSION_TWEAK,
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
']','\0'};
|
||||
#endif
|
||||
|
||||
/* Construct a string literal encoding the internal version number. */
|
||||
#ifdef COMPILER_VERSION_INTERNAL
|
||||
char const info_version_internal[] = {
|
||||
'I', 'N', 'F', 'O', ':',
|
||||
'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
|
||||
'i','n','t','e','r','n','a','l','[',
|
||||
COMPILER_VERSION_INTERNAL,']','\0'};
|
||||
#elif defined(COMPILER_VERSION_INTERNAL_STR)
|
||||
char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";
|
||||
#endif
|
||||
|
||||
/* Construct a string literal encoding the version number components. */
|
||||
#ifdef SIMULATE_VERSION_MAJOR
|
||||
char const info_simulate_version[] = {
|
||||
'I', 'N', 'F', 'O', ':',
|
||||
's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',
|
||||
SIMULATE_VERSION_MAJOR,
|
||||
# ifdef SIMULATE_VERSION_MINOR
|
||||
'.', SIMULATE_VERSION_MINOR,
|
||||
# ifdef SIMULATE_VERSION_PATCH
|
||||
'.', SIMULATE_VERSION_PATCH,
|
||||
# ifdef SIMULATE_VERSION_TWEAK
|
||||
'.', SIMULATE_VERSION_TWEAK,
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
']','\0'};
|
||||
#endif
|
||||
|
||||
/* Construct the string literal in pieces to prevent the source from
|
||||
getting matched. Store it in a pointer rather than an array
|
||||
because some compilers will just produce instructions to fill the
|
||||
array rather than assigning a pointer to a static array. */
|
||||
char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
|
||||
char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
|
||||
|
||||
|
||||
|
||||
#define CXX_STD_98 199711L
|
||||
#define CXX_STD_11 201103L
|
||||
#define CXX_STD_14 201402L
|
||||
#define CXX_STD_17 201703L
|
||||
#define CXX_STD_20 202002L
|
||||
#define CXX_STD_23 202302L
|
||||
|
||||
#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG)
|
||||
# if _MSVC_LANG > CXX_STD_17
|
||||
# define CXX_STD _MSVC_LANG
|
||||
# elif _MSVC_LANG == CXX_STD_17 && defined(__cpp_aggregate_paren_init)
|
||||
# define CXX_STD CXX_STD_20
|
||||
# elif _MSVC_LANG > CXX_STD_14 && __cplusplus > CXX_STD_17
|
||||
# define CXX_STD CXX_STD_20
|
||||
# elif _MSVC_LANG > CXX_STD_14
|
||||
# define CXX_STD CXX_STD_17
|
||||
# elif defined(__INTEL_CXX11_MODE__) && defined(__cpp_aggregate_nsdmi)
|
||||
# define CXX_STD CXX_STD_14
|
||||
# elif defined(__INTEL_CXX11_MODE__)
|
||||
# define CXX_STD CXX_STD_11
|
||||
# else
|
||||
# define CXX_STD CXX_STD_98
|
||||
# endif
|
||||
#elif defined(_MSC_VER) && defined(_MSVC_LANG)
|
||||
# if _MSVC_LANG > __cplusplus
|
||||
# define CXX_STD _MSVC_LANG
|
||||
# else
|
||||
# define CXX_STD __cplusplus
|
||||
# endif
|
||||
#elif defined(__NVCOMPILER)
|
||||
# if __cplusplus == CXX_STD_17 && defined(__cpp_aggregate_paren_init)
|
||||
# define CXX_STD CXX_STD_20
|
||||
# else
|
||||
# define CXX_STD __cplusplus
|
||||
# endif
|
||||
#elif defined(__INTEL_COMPILER) || defined(__PGI)
|
||||
# if __cplusplus == CXX_STD_11 && defined(__cpp_namespace_attributes)
|
||||
# define CXX_STD CXX_STD_17
|
||||
# elif __cplusplus == CXX_STD_11 && defined(__cpp_aggregate_nsdmi)
|
||||
# define CXX_STD CXX_STD_14
|
||||
# else
|
||||
# define CXX_STD __cplusplus
|
||||
# endif
|
||||
#elif (defined(__IBMCPP__) || defined(__ibmxl__)) && defined(__linux__)
|
||||
# if __cplusplus == CXX_STD_11 && defined(__cpp_aggregate_nsdmi)
|
||||
# define CXX_STD CXX_STD_14
|
||||
# else
|
||||
# define CXX_STD __cplusplus
|
||||
# endif
|
||||
#elif __cplusplus == 1 && defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define CXX_STD CXX_STD_11
|
||||
#else
|
||||
# define CXX_STD __cplusplus
|
||||
#endif
|
||||
|
||||
const char* info_language_standard_default = "INFO" ":" "standard_default["
|
||||
#if CXX_STD > CXX_STD_23
|
||||
"26"
|
||||
#elif CXX_STD > CXX_STD_20
|
||||
"23"
|
||||
#elif CXX_STD > CXX_STD_17
|
||||
"20"
|
||||
#elif CXX_STD > CXX_STD_14
|
||||
"17"
|
||||
#elif CXX_STD > CXX_STD_11
|
||||
"14"
|
||||
#elif CXX_STD >= CXX_STD_11
|
||||
"11"
|
||||
#else
|
||||
"98"
|
||||
#endif
|
||||
"]";
|
||||
|
||||
const char* info_language_extensions_default = "INFO" ":" "extensions_default["
|
||||
#if (defined(__clang__) || defined(__GNUC__) || defined(__xlC__) || \
|
||||
defined(__TI_COMPILER_VERSION__) || defined(__RENESAS__)) && \
|
||||
!defined(__STRICT_ANSI__)
|
||||
"ON"
|
||||
#else
|
||||
"OFF"
|
||||
#endif
|
||||
"]";
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int require = 0;
|
||||
require += info_compiler[argc];
|
||||
require += info_platform[argc];
|
||||
require += info_arch[argc];
|
||||
#ifdef COMPILER_VERSION_MAJOR
|
||||
require += info_version[argc];
|
||||
#endif
|
||||
#if defined(COMPILER_VERSION_INTERNAL) || defined(COMPILER_VERSION_INTERNAL_STR)
|
||||
require += info_version_internal[argc];
|
||||
#endif
|
||||
#ifdef SIMULATE_ID
|
||||
require += info_simulate[argc];
|
||||
#endif
|
||||
#ifdef SIMULATE_VERSION_MAJOR
|
||||
require += info_simulate_version[argc];
|
||||
#endif
|
||||
#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)
|
||||
require += info_cray[argc];
|
||||
#endif
|
||||
require += info_language_standard_default[argc];
|
||||
require += info_language_extensions_default[argc];
|
||||
(void)argv;
|
||||
return require;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"InstallScripts" :
|
||||
[
|
||||
"/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/cmake_install.cmake"
|
||||
],
|
||||
"Parallel" : false
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/saqut.dir
|
||||
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/edit_cache.dir
|
||||
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/rebuild_cache.dir
|
||||
|
|
@ -0,0 +1 @@
|
|||
# This file is generated by cmake for dependency checking of the CMakeCache.txt file
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
# CMAKE generated file: DO NOT EDIT!
|
||||
# Generated by "Ninja" Generator, CMake Version 4.3
|
||||
|
||||
# This file contains all the rules used to get the outputs files
|
||||
# built from the input files.
|
||||
# It is included in the main 'build.ninja'.
|
||||
|
||||
# =============================================================================
|
||||
# Project: saqut
|
||||
# Configurations: Debug
|
||||
# =============================================================================
|
||||
# =============================================================================
|
||||
|
||||
#############################################
|
||||
# Rule for generating CXX dependencies.
|
||||
|
||||
rule CXX_SCAN__saqut_Debug
|
||||
depfile = $DEP_FILE
|
||||
command = /usr/bin/c++ $DEFINES $INCLUDES $FLAGS -E -x c++ $in -MT $DYNDEP_INTERMEDIATE_FILE -MD -MF $DEP_FILE -fmodules-ts -fdeps-file=$DYNDEP_INTERMEDIATE_FILE -fdeps-target=$OBJ_FILE -fdeps-format=p1689r5 -o $PREPROCESSED_OUTPUT_FILE
|
||||
description = Scanning $in for CXX dependencies
|
||||
|
||||
|
||||
#############################################
|
||||
# Rule to generate ninja dyndep files for CXX.
|
||||
|
||||
rule CXX_DYNDEP__saqut_Debug
|
||||
command = /usr/bin/cmake -E cmake_ninja_dyndep --tdi=CMakeFiles/saqut.dir/CXXDependInfo.json --lang=CXX --modmapfmt=gcc --dd=$out @$out.rsp
|
||||
description = Generating CXX dyndep file $out
|
||||
rspfile = $out.rsp
|
||||
rspfile_content = $in
|
||||
restat = 1
|
||||
|
||||
|
||||
#############################################
|
||||
# Rule for compiling CXX files.
|
||||
|
||||
rule CXX_COMPILER__saqut_scanned_Debug
|
||||
depfile = $DEP_FILE
|
||||
deps = gcc
|
||||
command = ${LAUNCHER}${CODE_CHECK}/usr/bin/c++ $DEFINES $INCLUDES $FLAGS -MD -MT $out -MF $DEP_FILE -fmodules-ts -fmodule-mapper=$DYNDEP_MODULE_MAP_FILE -MD -fdeps-format=p1689r5 -x c++ -o $out -c $in
|
||||
description = Building CXX object $out
|
||||
|
||||
|
||||
#############################################
|
||||
# Rule for compiling CXX files.
|
||||
|
||||
rule CXX_COMPILER__saqut_unscanned_Debug
|
||||
depfile = $DEP_FILE
|
||||
deps = gcc
|
||||
command = ${LAUNCHER}${CODE_CHECK}/usr/bin/c++ $DEFINES $INCLUDES $FLAGS -MD -MT $out -MF $DEP_FILE -o $out -c $in
|
||||
description = Building CXX object $out
|
||||
|
||||
|
||||
#############################################
|
||||
# Rule for linking CXX executable.
|
||||
|
||||
rule CXX_EXECUTABLE_LINKER__saqut_Debug
|
||||
depfile = $DEP_FILE
|
||||
deps = gcc
|
||||
command = $PRE_LINK && /usr/bin/c++ $FLAGS $LINK_FLAGS $in -o $TARGET_FILE $LINK_PATH $LINK_LIBRARIES && $POST_BUILD
|
||||
description = Linking CXX executable $TARGET_FILE
|
||||
restat = $RESTAT
|
||||
|
||||
|
||||
#############################################
|
||||
# Rule for running custom commands.
|
||||
|
||||
rule CUSTOM_COMMAND
|
||||
command = $COMMAND
|
||||
description = $DESC
|
||||
|
||||
|
||||
#############################################
|
||||
# Rule for re-running cmake.
|
||||
|
||||
rule RERUN_CMAKE
|
||||
command = /usr/bin/cmake --regenerate-during-build -S/home/saqut/Masaüstü/saqutcompiler -B/home/saqut/Masaüstü/saqutcompiler/build
|
||||
description = Re-running CMake...
|
||||
generator = 1
|
||||
|
||||
|
||||
#############################################
|
||||
# Rule for cleaning all built files.
|
||||
|
||||
rule CLEAN
|
||||
command = /usr/bin/ninja $FILE_ARG -t clean $TARGETS
|
||||
description = Cleaning all built files...
|
||||
|
||||
|
||||
#############################################
|
||||
# Rule for printing all primary targets available.
|
||||
|
||||
rule HELP
|
||||
command = /usr/bin/ninja -t targets
|
||||
description = All primary targets available:
|
||||
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
# CMAKE generated file: DO NOT EDIT!
|
||||
# Generated by "Ninja" Generator, CMake Version 4.3
|
||||
|
||||
# This file contains all the build statements describing the
|
||||
# compilation DAG.
|
||||
|
||||
# =============================================================================
|
||||
# Write statements declared in CMakeLists.txt:
|
||||
#
|
||||
# Which is the root file.
|
||||
# =============================================================================
|
||||
|
||||
# =============================================================================
|
||||
# Project: saqut
|
||||
# Configurations: Debug
|
||||
# =============================================================================
|
||||
|
||||
#############################################
|
||||
# Minimal version of Ninja required by this file
|
||||
|
||||
ninja_required_version = 1.5
|
||||
|
||||
|
||||
#############################################
|
||||
# Set configuration variable for custom commands.
|
||||
|
||||
CONFIGURATION = Debug
|
||||
# =============================================================================
|
||||
# Include auxiliary files.
|
||||
|
||||
|
||||
#############################################
|
||||
# Include rules file.
|
||||
|
||||
include CMakeFiles/rules.ninja
|
||||
|
||||
# =============================================================================
|
||||
|
||||
#############################################
|
||||
# Logical path to working directory; prefix for absolute paths.
|
||||
|
||||
cmake_ninja_workdir = /home/saqut/Masaüstü/saqutcompiler/build/
|
||||
# =============================================================================
|
||||
# Object build statements for EXECUTABLE target saqut
|
||||
|
||||
|
||||
#############################################
|
||||
# Order-only phony target for saqut
|
||||
|
||||
build cmake_object_order_depends_target_saqut: phony || .
|
||||
|
||||
build CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/core/sourcefile.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/core
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/lexer/lexer.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/lexer
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/main.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/main.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/main.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/binary_expr.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/declarations.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/expressions.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/identifier.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/literal.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/program.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/statements.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/parser/parser.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/parser.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/parser/parser.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
build CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/tokenizer/tokenizer.cpp || cmake_object_order_depends_target_saqut
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o.d
|
||||
FLAGS = -g -std=gnu++20 -Wall -Wextra -g -O0
|
||||
INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/tokenizer
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Link build statements for EXECUTABLE target saqut
|
||||
|
||||
|
||||
#############################################
|
||||
# Link the executable saqut
|
||||
|
||||
build saqut: CXX_EXECUTABLE_LINKER__saqut_Debug CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o CMakeFiles/saqut.dir/src/main.cpp.o CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o CMakeFiles/saqut.dir/src/parser/parser.cpp.o CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o
|
||||
CONFIG = Debug
|
||||
DEP_FILE = CMakeFiles/saqut.dir/link.d
|
||||
FLAGS = -g
|
||||
LINK_FLAGS = -Wl,--dependency-file=CMakeFiles/saqut.dir/link.d
|
||||
OBJECT_DIR = CMakeFiles/saqut.dir
|
||||
POST_BUILD = :
|
||||
PRE_LINK = :
|
||||
TARGET_FILE = saqut
|
||||
TARGET_PDB = saqut.dbg
|
||||
TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir
|
||||
|
||||
|
||||
#############################################
|
||||
# Utility command for edit_cache
|
||||
|
||||
build CMakeFiles/edit_cache.util: CUSTOM_COMMAND
|
||||
COMMAND = cd /home/saqut/Masaüstü/saqutcompiler/build && /usr/bin/ccmake -S/home/saqut/Masaüstü/saqutcompiler -B/home/saqut/Masaüstü/saqutcompiler/build
|
||||
DESC = Running CMake cache editor...
|
||||
pool = console
|
||||
restat = 1
|
||||
|
||||
build edit_cache: phony CMakeFiles/edit_cache.util
|
||||
|
||||
|
||||
#############################################
|
||||
# Utility command for rebuild_cache
|
||||
|
||||
build CMakeFiles/rebuild_cache.util: CUSTOM_COMMAND
|
||||
COMMAND = cd /home/saqut/Masaüstü/saqutcompiler/build && /usr/bin/cmake --regenerate-during-build -S/home/saqut/Masaüstü/saqutcompiler -B/home/saqut/Masaüstü/saqutcompiler/build
|
||||
DESC = Running CMake to regenerate build system...
|
||||
pool = console
|
||||
restat = 1
|
||||
|
||||
build rebuild_cache: phony CMakeFiles/rebuild_cache.util
|
||||
|
||||
# =============================================================================
|
||||
# Target aliases.
|
||||
|
||||
# =============================================================================
|
||||
# Folder targets.
|
||||
|
||||
# =============================================================================
|
||||
|
||||
#############################################
|
||||
# Folder: /home/saqut/Masaüstü/saqutcompiler/build
|
||||
|
||||
build all: phony saqut
|
||||
|
||||
# =============================================================================
|
||||
# Built-in targets
|
||||
|
||||
|
||||
#############################################
|
||||
# Re-run CMake if any of its inputs changed.
|
||||
|
||||
build build.ninja /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake: RERUN_CMAKE | /home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt /usr/share/cmake/Modules/CMakeCXXInformation.cmake /usr/share/cmake/Modules/CMakeCommonLanguageInclude.cmake /usr/share/cmake/Modules/CMakeGenericSystem.cmake /usr/share/cmake/Modules/CMakeInitializeConfigs.cmake /usr/share/cmake/Modules/CMakeLanguageInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInitialize.cmake /usr/share/cmake/Modules/Compiler/CMakeCommonCompilerMacros.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX.cmake /usr/share/cmake/Modules/Compiler/GNU.cmake /usr/share/cmake/Modules/Internal/CMakeCXXLinkerInformation.cmake /usr/share/cmake/Modules/Internal/CMakeCommonLinkerInformation.cmake /usr/share/cmake/Modules/Linker/GNU-CXX.cmake /usr/share/cmake/Modules/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-Initialize.cmake /usr/share/cmake/Modules/Platform/Linux.cmake /usr/share/cmake/Modules/Platform/UnixPaths.cmake CMakeCache.txt CMakeFiles/4.3.2/CMakeCXXCompiler.cmake CMakeFiles/4.3.2/CMakeSystem.cmake
|
||||
pool = console
|
||||
|
||||
|
||||
#############################################
|
||||
# A missing CMake input file is not an error.
|
||||
|
||||
build /home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt /usr/share/cmake/Modules/CMakeCXXInformation.cmake /usr/share/cmake/Modules/CMakeCommonLanguageInclude.cmake /usr/share/cmake/Modules/CMakeGenericSystem.cmake /usr/share/cmake/Modules/CMakeInitializeConfigs.cmake /usr/share/cmake/Modules/CMakeLanguageInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInitialize.cmake /usr/share/cmake/Modules/Compiler/CMakeCommonCompilerMacros.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX.cmake /usr/share/cmake/Modules/Compiler/GNU.cmake /usr/share/cmake/Modules/Internal/CMakeCXXLinkerInformation.cmake /usr/share/cmake/Modules/Internal/CMakeCommonLinkerInformation.cmake /usr/share/cmake/Modules/Linker/GNU-CXX.cmake /usr/share/cmake/Modules/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-Initialize.cmake /usr/share/cmake/Modules/Platform/Linux.cmake /usr/share/cmake/Modules/Platform/UnixPaths.cmake CMakeCache.txt CMakeFiles/4.3.2/CMakeCXXCompiler.cmake CMakeFiles/4.3.2/CMakeSystem.cmake: phony
|
||||
|
||||
|
||||
#############################################
|
||||
# Clean all the built files.
|
||||
|
||||
build clean: CLEAN
|
||||
|
||||
|
||||
#############################################
|
||||
# Print all primary targets available.
|
||||
|
||||
build help: HELP
|
||||
|
||||
|
||||
#############################################
|
||||
# Make the all target the default.
|
||||
|
||||
default all
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
# Install script for directory: /home/saqut/Masaüstü/saqutcompiler
|
||||
|
||||
# Set the install prefix
|
||||
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
|
||||
set(CMAKE_INSTALL_PREFIX "/usr/local")
|
||||
endif()
|
||||
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
# Set the install configuration name.
|
||||
if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
|
||||
if(BUILD_TYPE)
|
||||
string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
|
||||
CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_CONFIG_NAME "Debug")
|
||||
endif()
|
||||
message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
|
||||
endif()
|
||||
|
||||
# Set the component getting installed.
|
||||
if(NOT CMAKE_INSTALL_COMPONENT)
|
||||
if(COMPONENT)
|
||||
message(STATUS "Install component: \"${COMPONENT}\"")
|
||||
set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_COMPONENT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Install shared libraries without execute permission?
|
||||
if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)
|
||||
set(CMAKE_INSTALL_SO_NO_EXE "0")
|
||||
endif()
|
||||
|
||||
# Is this installation the result of a crosscompile?
|
||||
if(NOT DEFINED CMAKE_CROSSCOMPILING)
|
||||
set(CMAKE_CROSSCOMPILING "FALSE")
|
||||
endif()
|
||||
|
||||
# Set path to fallback-tool for dependency-resolution.
|
||||
if(NOT DEFINED CMAKE_OBJDUMP)
|
||||
set(CMAKE_OBJDUMP "/usr/bin/objdump")
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT
|
||||
"${CMAKE_INSTALL_MANIFEST_FILES}")
|
||||
if(CMAKE_INSTALL_LOCAL_ONLY)
|
||||
file(WRITE "/home/saqut/Masaüstü/saqutcompiler/build/install_local_manifest.txt"
|
||||
"${CMAKE_INSTALL_MANIFEST_CONTENT}")
|
||||
endif()
|
||||
if(CMAKE_INSTALL_COMPONENT)
|
||||
if(CMAKE_INSTALL_COMPONENT MATCHES "^[a-zA-Z0-9_.+-]+$")
|
||||
set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt")
|
||||
else()
|
||||
string(MD5 CMAKE_INST_COMP_HASH "${CMAKE_INSTALL_COMPONENT}")
|
||||
set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INST_COMP_HASH}.txt")
|
||||
unset(CMAKE_INST_COMP_HASH)
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_INSTALL_MANIFEST "install_manifest.txt")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_LOCAL_ONLY)
|
||||
file(WRITE "/home/saqut/Masaüstü/saqutcompiler/build/${CMAKE_INSTALL_MANIFEST}"
|
||||
"${CMAKE_INSTALL_MANIFEST_CONTENT}")
|
||||
endif()
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." &> /dev/null && pwd )"
|
||||
BUILD_DIR="$PROJECT_ROOT/build"
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
|
||||
ninja
|
||||
echo "Derleme başarılı: build/saqut"
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#include "core/sourcefile.hpp"
|
||||
|
||||
void SourceFile::setText(const std::string& path, const std::string& source) {
|
||||
filePath = path;
|
||||
text = source;
|
||||
computeLineStarts();
|
||||
}
|
||||
|
||||
int SourceFile::lineCount() const {
|
||||
return static_cast<int>(lineStarts.size());
|
||||
}
|
||||
|
||||
std::string SourceFile::getLine(int line) const {
|
||||
if (line < 1 || line > lineCount()) return "";
|
||||
int start = lineStarts[line - 1];
|
||||
int end;
|
||||
if (line < lineCount()) {
|
||||
end = lineStarts[line] - 1; // Satır sonu (\n) hariç
|
||||
// \r\n varsa bir karakter daha geri
|
||||
if (end > start && text[end - 1] == '\r') end--;
|
||||
} else {
|
||||
end = static_cast<int>(text.length());
|
||||
}
|
||||
return text.substr(start, end - start);
|
||||
}
|
||||
|
||||
SourceLocation SourceFile::offsetToLocation(int offset) const {
|
||||
// Geçersiz offset kontrolü
|
||||
if (offset < 0 || offset > static_cast<int>(text.length())) {
|
||||
return SourceLocation{filePath, 0, 0, -1};
|
||||
}
|
||||
|
||||
// Binary search: offset'in hangi satıra ait olduğunu bul
|
||||
// lineStarts içinde offset'ten büyük ilk elemanı bul
|
||||
auto it = std::upper_bound(lineStarts.begin(), lineStarts.end(), offset);
|
||||
int lineIndex = static_cast<int>(it - lineStarts.begin()) - 1;
|
||||
|
||||
// lineIndex geçerli değilse
|
||||
if (lineIndex < 0) {
|
||||
lineIndex = 0;
|
||||
} else if (lineIndex >= static_cast<int>(lineStarts.size())) {
|
||||
lineIndex = static_cast<int>(lineStarts.size()) - 1;
|
||||
}
|
||||
|
||||
int lineStart = lineStarts[lineIndex];
|
||||
int line = lineIndex + 1; // 1-tabanlı
|
||||
int column = offset - lineStart + 1; // 1-tabanlı
|
||||
|
||||
return SourceLocation{filePath, line, column, offset};
|
||||
}
|
||||
|
||||
SourceFile::LocationRange SourceFile::rangeFromOffsets(int startOffset, int endOffset) const {
|
||||
return {offsetToLocation(startOffset), offsetToLocation(endOffset)};
|
||||
}
|
||||
|
||||
void SourceFile::computeLineStarts() {
|
||||
lineStarts.clear();
|
||||
lineStarts.push_back(0); // 1. satır offset 0
|
||||
|
||||
for (int i = 0; i < static_cast<int>(text.length()); i++) {
|
||||
if (text[i] == '\n') {
|
||||
// \r\n kontrolü: \r'yi atla, \n'den sonraki karakter yeni satır
|
||||
int nextStart = i + 1;
|
||||
if (nextStart < static_cast<int>(text.length())) {
|
||||
lineStarts.push_back(nextStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -54,58 +54,17 @@ public:
|
|||
SourceFile() = default;
|
||||
|
||||
// text verisini yeni satır dizisini de hesapla
|
||||
void setText(const std::string& path, const std::string& source) {
|
||||
filePath = path;
|
||||
text = source;
|
||||
computeLineStarts();
|
||||
}
|
||||
void setText(const std::string& path, const std::string& source);
|
||||
|
||||
// Kaynak kodun toplam satır sayısı
|
||||
int lineCount() const {
|
||||
return static_cast<int>(lineStarts.size());
|
||||
}
|
||||
int lineCount() const;
|
||||
|
||||
// Belirtilen offset'teki satırın tam metnini döndür
|
||||
std::string getLine(int line) const {
|
||||
if (line < 1 || line > lineCount()) return "";
|
||||
int start = lineStarts[line - 1];
|
||||
int end;
|
||||
if (line < lineCount()) {
|
||||
end = lineStarts[line] - 1; // Satır sonu (\n) hariç
|
||||
// \r\n varsa bir karakter daha geri
|
||||
if (end > start && text[end - 1] == '\r') end--;
|
||||
} else {
|
||||
end = static_cast<int>(text.length());
|
||||
}
|
||||
return text.substr(start, end - start);
|
||||
}
|
||||
std::string getLine(int line) const;
|
||||
|
||||
// Offset'ten (line, column) dönüşümü
|
||||
// Binary search ile O(log n)
|
||||
SourceLocation offsetToLocation(int offset) const {
|
||||
// Geçersiz offset kontrolü
|
||||
if (offset < 0 || offset > static_cast<int>(text.length())) {
|
||||
return SourceLocation{filePath, 0, 0, -1};
|
||||
}
|
||||
|
||||
// Binary search: offset'in hangi satıra ait olduğunu bul
|
||||
// lineStarts içinde offset'ten büyük ilk elemanı bul
|
||||
auto it = std::upper_bound(lineStarts.begin(), lineStarts.end(), offset);
|
||||
int lineIndex = static_cast<int>(it - lineStarts.begin()) - 1;
|
||||
|
||||
// lineIndex geçerli değilse
|
||||
if (lineIndex < 0) {
|
||||
lineIndex = 0;
|
||||
} else if (lineIndex >= static_cast<int>(lineStarts.size())) {
|
||||
lineIndex = static_cast<int>(lineStarts.size()) - 1;
|
||||
}
|
||||
|
||||
int lineStart = lineStarts[lineIndex];
|
||||
int line = lineIndex + 1; // 1-tabanlı
|
||||
int column = offset - lineStart + 1; // 1-tabanlı
|
||||
|
||||
return SourceLocation{filePath, line, column, offset};
|
||||
}
|
||||
SourceLocation offsetToLocation(int offset) const;
|
||||
|
||||
// Bir aralığın başlangıç ve bitiş konumlarını döndür
|
||||
struct LocationRange {
|
||||
|
|
@ -113,28 +72,13 @@ public:
|
|||
SourceLocation end;
|
||||
};
|
||||
|
||||
LocationRange rangeFromOffsets(int startOffset, int endOffset) const {
|
||||
return {offsetToLocation(startOffset), offsetToLocation(endOffset)};
|
||||
}
|
||||
LocationRange rangeFromOffsets(int startOffset, int endOffset) const;
|
||||
|
||||
private:
|
||||
// lineStarts vektörünü hesapla
|
||||
// Her \n karakterinden sonraki offset bir sonraki satırın başlangıcıdır
|
||||
// İlk satır her zaman offset 0'dan başlar
|
||||
void computeLineStarts() {
|
||||
lineStarts.clear();
|
||||
lineStarts.push_back(0); // 1. satır offset 0
|
||||
|
||||
for (int i = 0; i < static_cast<int>(text.length()); i++) {
|
||||
if (text[i] == '\n') {
|
||||
// \r\n kontrolü: \r'yi atla, \n'den sonraki karakter yeni satır
|
||||
int nextStart = i + 1;
|
||||
if (nextStart < static_cast<int>(text.length())) {
|
||||
lineStarts.push_back(nextStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void computeLineStarts();
|
||||
};
|
||||
|
||||
#endif // SAQUT_CORE_SOURCEFILE
|
||||
|
|
|
|||
|
|
@ -0,0 +1,346 @@
|
|||
#include "lexer/lexer.hpp"
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// beginPosition: Mevcut offset'i yığına kaydet.
|
||||
// İç içe çağrılabilir: 3 kere beginPosition → 3 elemanlı yığın.
|
||||
// --------------------------------------------------------------------------
|
||||
void Lexer::beginPosition() {
|
||||
offsetMap.push_back(getLastPosition());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getLastPosition: Yığının tepesindeki konumu döndür.
|
||||
// Yığın boşsa mevcut offset'i döndür (başlangıç durumu).
|
||||
// --------------------------------------------------------------------------
|
||||
int Lexer::getLastPosition() {
|
||||
if (offsetMap.empty()) return offset;
|
||||
return offsetMap.back();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// acceptPosition: Yığındaki son geçici konumu kalıcı yap.
|
||||
// Örnek: offsetMap=[5,10], offset=15 → offsetMap.back()=10 olur.
|
||||
// Bu sayede include() denemesi başarılı olduğunda konum ilerletilmiş olur.
|
||||
// --------------------------------------------------------------------------
|
||||
void Lexer::acceptPosition() {
|
||||
int t = offsetMap.back();
|
||||
setLastPosition(t);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// setLastPosition: Yığının tepesini veya offset'i değiştir.
|
||||
// --------------------------------------------------------------------------
|
||||
void Lexer::setLastPosition(int n) {
|
||||
if (offsetMap.empty())
|
||||
offset = n;
|
||||
else
|
||||
offsetMap.back() = n;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// isEnd: Dosya sonuna gelindi mi? offset >= size.
|
||||
// --------------------------------------------------------------------------
|
||||
bool Lexer::isEnd() {
|
||||
return size <= getOffset();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// rejectPosition: Yığındaki son konumu at. Başarısız include() denemesi sonrası.
|
||||
// --------------------------------------------------------------------------
|
||||
void Lexer::rejectPosition() {
|
||||
offsetMap.pop_back();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// positionRange: Yığındaki en dış ve en iç konumu [start, end] olarak döndür.
|
||||
// UYARI: new int[2] ile heap'te tahsis eder. Çağıran sorumludur.
|
||||
// TODO: std::pair<int,int> veya yapı kullanarak tahsisi kaldır.
|
||||
// --------------------------------------------------------------------------
|
||||
int* Lexer::positionRange() {
|
||||
int len = offsetMap.size();
|
||||
if (len == 0)
|
||||
return new int[2]{0, offset};
|
||||
if (len == 1)
|
||||
return new int[2]{offset, offsetMap[0]};
|
||||
return new int[2]{offsetMap[len - 2], offsetMap[len - 1]};
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getPositionRange: positionRange() aralığındaki metni string olarak döndür.
|
||||
// --------------------------------------------------------------------------
|
||||
std::string Lexer::getPositionRange() {
|
||||
int* a = positionRange();
|
||||
std::string mem;
|
||||
for (int i = a[0]; i < a[1]; i++)
|
||||
mem.push_back(input.at(i));
|
||||
return mem;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// include: Belirtilen kelime mevcut konumda başlıyor mu?
|
||||
// --------------------------------------------------------------------------
|
||||
bool Lexer::include(std::string word, bool accept) {
|
||||
beginPosition();
|
||||
for (size_t i = 0; i < word.size(); i++) {
|
||||
if (isEnd()) {
|
||||
rejectPosition();
|
||||
return false;
|
||||
}
|
||||
if (word[i] != getchar()) {
|
||||
rejectPosition();
|
||||
return false;
|
||||
}
|
||||
nextChar();
|
||||
}
|
||||
if (accept)
|
||||
acceptPosition();
|
||||
else
|
||||
rejectPosition();
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getOffset / setOffset: Konum erişimcileri.
|
||||
// --------------------------------------------------------------------------
|
||||
int Lexer::getOffset() {
|
||||
return getLastPosition();
|
||||
}
|
||||
|
||||
int Lexer::setOffset(int n) {
|
||||
setLastPosition(n);
|
||||
return getLastPosition();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getchar(additionalOffset): offset + ek kadar ilerideki karakteri oku.
|
||||
// --------------------------------------------------------------------------
|
||||
char Lexer::getchar(int additionalOffset) {
|
||||
int target = getOffset() + additionalOffset;
|
||||
if (target >= size) {
|
||||
std::cerr << "Lexer hatası: sınır aşımı\n";
|
||||
return '\0';
|
||||
}
|
||||
return input.at(target);
|
||||
}
|
||||
|
||||
char Lexer::getchar() {
|
||||
int target = getOffset();
|
||||
if (target >= size) {
|
||||
std::cerr << "Lexer hatası: sınır aşımı\n";
|
||||
return '\0';
|
||||
}
|
||||
return input.at(target);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// nextChar / toChar: Konum ilerletme.
|
||||
// --------------------------------------------------------------------------
|
||||
void Lexer::nextChar() {
|
||||
if (!isEnd())
|
||||
setOffset(getOffset() + 1);
|
||||
}
|
||||
|
||||
void Lexer::toChar(int n) {
|
||||
if (!isEnd())
|
||||
setOffset(getOffset() + n);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getLocation: Mevcut offset'in SourceLocation'ını döndür.
|
||||
// --------------------------------------------------------------------------
|
||||
SourceLocation Lexer::getLocation() {
|
||||
return sourceFile.offsetToLocation(getOffset());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// setSourceText: Yeni kaynak kodu yükle ve SourceFile'ı güncelle.
|
||||
// --------------------------------------------------------------------------
|
||||
void Lexer::setSourceText(const std::string& path, const std::string& text) {
|
||||
sourceFile.setText(path, text);
|
||||
setText(text);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// setText: Yeni kaynak kodu yükle. input ve size'ı günceller.
|
||||
// --------------------------------------------------------------------------
|
||||
void Lexer::setText(std::string text) {
|
||||
input = text;
|
||||
size = static_cast<int>(text.length());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// skipWhiteSpace: Boşluk, sekme, satırsonu, satırbaşı karakterlerini atla.
|
||||
// --------------------------------------------------------------------------
|
||||
void Lexer::skipWhiteSpace() {
|
||||
while (!isEnd()) {
|
||||
switch (getchar()) {
|
||||
case '\r': // carriage return (Windows satırsonu \r\n)
|
||||
case '\n': // line feed (Unix satırsonu)
|
||||
case '\b': // backspace
|
||||
case '\t': // tab
|
||||
case ' ': // boşluk
|
||||
nextChar();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// isNumeric: Mevcut karakter bir rakam mı? (0-9)
|
||||
// --------------------------------------------------------------------------
|
||||
bool Lexer::isNumeric() {
|
||||
char c = getchar();
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// readNumeric: Tam bir sayı literal'ı oku.
|
||||
// --------------------------------------------------------------------------
|
||||
INumber Lexer::readNumeric() {
|
||||
INumber num;
|
||||
num.start = getLastPosition();
|
||||
num.startLoc = getLocation();
|
||||
|
||||
// --- Adım 1: İsteğe bağlı işaret ---
|
||||
if (getchar() == '-') {
|
||||
nextChar();
|
||||
num.positive = false;
|
||||
} else if (getchar() == '+') {
|
||||
nextChar();
|
||||
num.positive = true;
|
||||
} else {
|
||||
num.positive = true;
|
||||
}
|
||||
|
||||
// --- Adım 2: İlk karakter '0' ise özel format kontrolü ---
|
||||
bool nextDot = false;
|
||||
if (getchar() == '0') {
|
||||
num.token.push_back('0');
|
||||
nextChar();
|
||||
char c = getchar();
|
||||
switch (c) {
|
||||
case 'x': case 'X': // Hex: 0xFF, 0X1A
|
||||
num.token.push_back(c);
|
||||
num.base = 16;
|
||||
nextChar();
|
||||
break;
|
||||
case 'b': case 'B': // Binary: 0b1010
|
||||
num.token.push_back(c);
|
||||
num.base = 2;
|
||||
nextChar();
|
||||
break;
|
||||
case '.': // Float: 0.5, 0.0
|
||||
num.token.push_back(c);
|
||||
num.base = 10;
|
||||
nextDot = true;
|
||||
num.isFloat = true;
|
||||
nextChar();
|
||||
break;
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7':
|
||||
// Octal: 0777 — sonraki karakter octal rakam ise devam et
|
||||
num.base = 8;
|
||||
break;
|
||||
default:
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
} else {
|
||||
num.base = 10;
|
||||
}
|
||||
|
||||
// --- Adım 3: Ana okuma döngüsü ---
|
||||
while (!isEnd()) {
|
||||
char c = getchar();
|
||||
switch (c) {
|
||||
case '0':
|
||||
case '1':
|
||||
num.token.push_back(c);
|
||||
break;
|
||||
case '2': case '3': case '4': case '5':
|
||||
case '6': case '7':
|
||||
if (num.base >= 8)
|
||||
num.token.push_back(c);
|
||||
else {
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
break;
|
||||
case '8': case '9':
|
||||
if (num.base >= 10)
|
||||
num.token.push_back(c);
|
||||
else {
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
break;
|
||||
case 'a': case 'A': case 'b': case 'B':
|
||||
case 'c': case 'C': case 'd': case 'D':
|
||||
case 'f': case 'F':
|
||||
if (num.base >= 16)
|
||||
num.token.push_back(c);
|
||||
else {
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
if (!nextDot) {
|
||||
if (num.token.empty())
|
||||
num.token += "0.";
|
||||
else
|
||||
num.token.push_back('.');
|
||||
nextDot = true;
|
||||
num.isFloat = true;
|
||||
} else {
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
break;
|
||||
case 'e': case 'E':
|
||||
if (num.base == 16) {
|
||||
num.token.push_back(c);
|
||||
break;
|
||||
}
|
||||
if (num.base == 10) {
|
||||
num.hasEpsilon = true;
|
||||
num.token.push_back(c);
|
||||
nextChar();
|
||||
c = getchar();
|
||||
if (c == '+' || c == '-') {
|
||||
num.token.push_back(c);
|
||||
nextChar();
|
||||
}
|
||||
while (!isEnd()) {
|
||||
c = getchar();
|
||||
if (c >= '0' && c <= '9') {
|
||||
num.token.push_back(c);
|
||||
nextChar();
|
||||
} else {
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
default:
|
||||
num.end = getLastPosition();
|
||||
return num;
|
||||
}
|
||||
nextChar();
|
||||
}
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
|
|
@ -15,46 +15,6 @@
|
|||
// 4. Boşluk karakterlerini atlar
|
||||
// 5. Satır/sütun bilgisi sağlar (hata mesajları için temel)
|
||||
//
|
||||
// ADR-006: Neden Kendi Lexer'ımız?
|
||||
// - std::istringstream veya regex kullanmak yerine, tam kontrol sağlayan
|
||||
// sıfırdan bir lexer yazdık.
|
||||
// - Backtracking: offsetMap ile konum yığını tutar, denenen bir eşleşme
|
||||
// başarısız olursa geri alınabilir. Bu özellik std::istream'de yoktur.
|
||||
// - Performans: Sanal fonksiyon çağrısı yok, her şey inline.
|
||||
// - Hata ayıklama: Her karakter okuması kontrol edilebilir.
|
||||
//
|
||||
// TASARIM KARARLARI:
|
||||
// 1. offsetMap (std::vector<int>): İç içe backtracking için yığın.
|
||||
// beginPosition() → yığına mevcut konumu ekler
|
||||
// acceptPosition() → yığındaki son konumu kalıcı yapar
|
||||
// rejectPosition() → yığındaki son konumu atar (geri al)
|
||||
// Bu sayede "dene, başarısız olursa geri al" patterni çalışır.
|
||||
//
|
||||
// 2. getchar() iki overload:
|
||||
// - getchar(): mevcut konumdaki karakteri okur
|
||||
// - getchar(int offset): mevcut konum + offset'teki karakteri okur
|
||||
// İkincisi özellikle keyword kontrolünde önemlidir:
|
||||
// "do" kelimesini gördükten sonra, bunun "double"ın başlangıcı olmadığını
|
||||
// kontrol etmek için keyword sonrası karaktere bakılır.
|
||||
//
|
||||
// 3. isEnd(): offset >= size ile kontrol. offset her zaman [0, size] aralığında.
|
||||
// size konumunda EOF (end of file) anlamına gelir.
|
||||
//
|
||||
// 4. readNumeric(): C/C++/Java sayı formatlarını destekler:
|
||||
// - Decimal: 42, -3, +7
|
||||
// - Hex: 0xFF, 0X1A
|
||||
// - Binary: 0b1010, 0B1100
|
||||
// - Octal: 0777 (0 ile başlayan ve 8-9 içermeyen)
|
||||
// - Float: 3.14, .5, 1e10, 2.5E-3
|
||||
// - Negatif/Pozitif: -42, +3 (baştaki işaret)
|
||||
//
|
||||
// BİLİNEN SINIRLAMALAR (TODO):
|
||||
// TODO: Satır/sütun takibi eklenmeli (şu anda sadece offset var)
|
||||
// TODO: Unicode/UTF-8 desteği (şu anda sadece ASCII)
|
||||
// TODO: ' char literal'ı okunamıyor
|
||||
// TODO: Sayısal alt çizgi (_) ayracı: 1_000_000 formatı
|
||||
// TODO: Binary floating point: 0b1.1p10 formatı (C99 hexfloat)
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_LEXER
|
||||
|
|
@ -69,25 +29,7 @@
|
|||
// ============================================================================
|
||||
// INumber — Ara Sayısal Veri Yapısı
|
||||
// ============================================================================
|
||||
//
|
||||
// Lexer'ın readNumeric() fonksiyonu tarafından döndürülür.
|
||||
// Tokenizer bu yapıyı NumberToken'a dönüştürür.
|
||||
//
|
||||
// Neden ayrı bir struct? Lexer katmanı Token sınıflarından haberdar değil.
|
||||
// Bağımlılık yönü: Lexer ← Tokenizer. Lexer hiçbir üst katmanı include etmez.
|
||||
//
|
||||
// ALANLAR:
|
||||
// start, end : Kaynak koddaki başlangıç/bitiş konumları (offset)
|
||||
// token : Sayının ham string hali (örn: "0xFF", "3.14", "1e10")
|
||||
// isFloat : Ondalıklı sayı mı? (nokta veya epsilon içeriyor mu)
|
||||
// hasEpsilon : Bilimsel gösterim mi? (e/E içeriyor mu)
|
||||
// base : Sayı tabanı: 2, 8, 10, veya 16
|
||||
// - 0x/0X ile başlarsa 16
|
||||
// - 0b/0B ile başlarsa 2
|
||||
// - 0 ile başlayıp 8-9 içermiyorsa 8
|
||||
// - diğer her şey 10
|
||||
// positive : Pozitif mi? (başında - işareti yoksa true)
|
||||
//
|
||||
|
||||
struct INumber {
|
||||
int start = 0; // Kaynak koddaki başlangıç offset'i
|
||||
int end = 0; // Kaynak koddaki bitiş offset'i
|
||||
|
|
@ -103,21 +45,7 @@ struct INumber {
|
|||
// ============================================================================
|
||||
// Lexer — Karakter Seviyesinde Tarayıcı
|
||||
// ============================================================================
|
||||
//
|
||||
// Derleyici pipeline'ının en alt katmanı. Ham string üzerinde çalışır.
|
||||
// Üst katmanlara (Tokenizer) karakter okuma ve konum yönetimi hizmeti sunar.
|
||||
//
|
||||
// DURUM DEĞİŞKENLERİ:
|
||||
// input : Taranan kaynak kodun tamamı (string kopyası, değişmez)
|
||||
// size : input.length() önbelleği (performans: her seferinde hesaplamaz)
|
||||
// offset : Mevcut okuma konumu. 0 = ilk karakter, size = EOF
|
||||
// offsetMap : Backtracking yığını. İç içe beginPosition/acceptPosition/rejectPosition
|
||||
//
|
||||
// PERFORMANS NOTU:
|
||||
// Tüm metotlar inline tanımlanmıştır. Sanal fonksiyon çağrısı yoktur.
|
||||
// offset değişiklikleri O(1)'dir.
|
||||
// include() metodu O(n) karakter karşılaştırması yapar (n = kelime uzunluğu).
|
||||
//
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
// --- Ham Veri ---
|
||||
|
|
@ -127,14 +55,6 @@ public:
|
|||
std::vector<int> offsetMap; // Backtracking yığını
|
||||
|
||||
// --- Pozisyon Yönetimi (Backtracking API) ---
|
||||
//
|
||||
// Kullanım örneği:
|
||||
// lexer.beginPosition(); // konumu kaydet
|
||||
// if (lexer.include("for", false)) // dene (false = eşleşse de geri al)
|
||||
// lexer.acceptPosition(); // başarılı → kalıcı yap
|
||||
// else
|
||||
// lexer.rejectPosition(); // başarısız → geri al
|
||||
|
||||
void beginPosition(); // Şu anki konumu yığına kaydet
|
||||
int getLastPosition(); // Yığındaki son konumu döndür
|
||||
void acceptPosition(); // Yığındaki son konumu kalıcı yap (apply)
|
||||
|
|
@ -147,10 +67,6 @@ public:
|
|||
std::string getPositionRange(); // Pozisyon aralığındaki metni döndür
|
||||
|
||||
// --- Desen Eşleme ---
|
||||
// include(): Belirtilen kelime mevcut konumda başlıyor mu?
|
||||
// accept=true (varsayılan): eşleşirse konum ilerletilir
|
||||
// accept=false: eşleşse bile konum geri alınır (keyword kontrolü için)
|
||||
// Örnek: include("for", false) → "for" ile başlıyor mu? konumu değiştirme.
|
||||
bool include(std::string word, bool accept = true);
|
||||
|
||||
// --- Konum Okuma/Yazma ---
|
||||
|
|
@ -164,7 +80,6 @@ public:
|
|||
void toChar(int n); // offset'i n kadar ilerlet
|
||||
|
||||
// --- Üst Seviye İşlemler ---
|
||||
// --- Konum Bilgisi (SourceFile üzerinden) ---
|
||||
SourceFile sourceFile; // Kaynak kod ve satır başı offset'leri
|
||||
SourceLocation getLocation(); // Mevcut offset'in SourceLocation'ını döndür
|
||||
void setSourceText(const std::string& path, const std::string& text);
|
||||
|
|
@ -175,423 +90,4 @@ public:
|
|||
INumber readNumeric(); // Sayı literal'ı oku ve INumber olarak döndür
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// GERÇEKLEME (Implementation)
|
||||
// ============================================================================
|
||||
// Tüm metotlar inline olarak aşağıda tanımlanmıştır.
|
||||
// Derleme modeli: header-only. main.cpp bu dosyayı include eder.
|
||||
// ============================================================================
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// beginPosition: Mevcut offset'i yığına kaydet.
|
||||
// İç içe çağrılabilir: 3 kere beginPosition → 3 elemanlı yığın.
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Lexer::beginPosition() {
|
||||
offsetMap.push_back(getLastPosition());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getLastPosition: Yığının tepesindeki konumu döndür.
|
||||
// Yığın boşsa mevcut offset'i döndür (başlangıç durumu).
|
||||
// --------------------------------------------------------------------------
|
||||
inline int Lexer::getLastPosition() {
|
||||
if (offsetMap.empty()) return offset;
|
||||
return offsetMap.back();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// acceptPosition: Yığındaki son geçici konumu kalıcı yap.
|
||||
// Örnek: offsetMap=[5,10], offset=15 → offsetMap.back()=10 olur.
|
||||
// Bu sayede include() denemesi başarılı olduğunda konum ilerletilmiş olur.
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Lexer::acceptPosition() {
|
||||
int t = offsetMap.back();
|
||||
setLastPosition(t);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// setLastPosition: Yığının tepesini veya offset'i değiştir.
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Lexer::setLastPosition(int n) {
|
||||
if (offsetMap.empty())
|
||||
offset = n;
|
||||
else
|
||||
offsetMap.back() = n;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// isEnd: Dosya sonuna gelindi mi? offset >= size.
|
||||
// --------------------------------------------------------------------------
|
||||
inline bool Lexer::isEnd() {
|
||||
return size <= getOffset();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// rejectPosition: Yığındaki son konumu at. Başarısız include() denemesi sonrası.
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Lexer::rejectPosition() {
|
||||
offsetMap.pop_back();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// positionRange: Yığındaki en dış ve en iç konumu [start, end] olarak döndür.
|
||||
// UYARI: new int[2] ile heap'te tahsis eder. Çağıran sorumludur.
|
||||
// TODO: std::pair<int,int> veya yapı kullanarak tahsisi kaldır.
|
||||
// --------------------------------------------------------------------------
|
||||
inline int* Lexer::positionRange() {
|
||||
int len = offsetMap.size();
|
||||
if (len == 0)
|
||||
return new int[2]{0, offset};
|
||||
if (len == 1)
|
||||
return new int[2]{offset, offsetMap[0]};
|
||||
return new int[2]{offsetMap[len - 2], offsetMap[len - 1]};
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getPositionRange: positionRange() aralığındaki metni string olarak döndür.
|
||||
// --------------------------------------------------------------------------
|
||||
inline std::string Lexer::getPositionRange() {
|
||||
int* a = positionRange();
|
||||
std::string mem;
|
||||
for (int i = a[0]; i < a[1]; i++)
|
||||
mem.push_back(input.at(i));
|
||||
return mem;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// include: Belirtilen kelime mevcut konumda başlıyor mu?
|
||||
//
|
||||
// Algoritma:
|
||||
// 1. beginPosition() ile konumu kaydet
|
||||
// 2. Kelimenin her karakterini sırayla karşılaştır
|
||||
// 3. Eşleşmezse veya EOF olursa → rejectPosition() ve false dön
|
||||
// 4. Tüm karakterler eşleşirse:
|
||||
// - accept=true ise → acceptPosition() (konum kalıcı ilerler)
|
||||
// - accept=false ise → rejectPosition() (konum eski haline döner)
|
||||
// 5. true dön
|
||||
//
|
||||
// Neden accept parametresi var?
|
||||
// Tokenizer scope() fonksiyonu, keyword'leri kontrol ederken accept=false
|
||||
// kullanır. Çünkü bir keyword eşleşmesi, aynı zamanda daha uzun bir
|
||||
// keyword'ün parçası olabilir (örn: "do", "double"ın başlangıcı).
|
||||
// Eğer include("do", true) kullanılırsa, konum ilerler ve geri alınamaz.
|
||||
// --------------------------------------------------------------------------
|
||||
inline bool Lexer::include(std::string word, bool accept) {
|
||||
beginPosition();
|
||||
for (size_t i = 0; i < word.size(); i++) {
|
||||
if (isEnd()) {
|
||||
rejectPosition();
|
||||
return false;
|
||||
}
|
||||
if (word[i] != getchar()) {
|
||||
rejectPosition();
|
||||
return false;
|
||||
}
|
||||
nextChar();
|
||||
}
|
||||
if (accept)
|
||||
acceptPosition();
|
||||
else
|
||||
rejectPosition();
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getOffset / setOffset: Konum erişimcileri.
|
||||
// --------------------------------------------------------------------------
|
||||
inline int Lexer::getOffset() {
|
||||
return getLastPosition();
|
||||
}
|
||||
|
||||
inline int Lexer::setOffset(int n) {
|
||||
setLastPosition(n);
|
||||
return getLastPosition();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getchar(additionalOffset): offset + ek kadar ilerideki karakteri oku.
|
||||
// Sınır kontrolü yapar: target >= size ise '\0' döndürür ve hata mesajı basar.
|
||||
// Bu metot özellikle keyword sınır kontrolünde kullanılır:
|
||||
// "do" eşleşti, sıradaki karakter 'u' ise bu "double" olabilir → keyword değil
|
||||
// --------------------------------------------------------------------------
|
||||
inline char Lexer::getchar(int additionalOffset) {
|
||||
int target = getOffset() + additionalOffset;
|
||||
if (target >= size) {
|
||||
std::cerr << "Lexer hatası: sınır aşımı\n";
|
||||
return '\0';
|
||||
}
|
||||
return input.at(target);
|
||||
}
|
||||
|
||||
inline char Lexer::getchar() {
|
||||
int target = getOffset();
|
||||
if (target >= size) {
|
||||
std::cerr << "Lexer hatası: sınır aşımı\n";
|
||||
return '\0';
|
||||
}
|
||||
return input.at(target);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// nextChar / toChar: Konum ilerletme.
|
||||
// EOF kontrolü yapar — dosya sonundaysa ilerlemez.
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Lexer::nextChar() {
|
||||
if (!isEnd())
|
||||
setOffset(getOffset() + 1);
|
||||
}
|
||||
|
||||
inline void Lexer::toChar(int n) {
|
||||
if (!isEnd())
|
||||
setOffset(getOffset() + n);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getLocation: Mevcut offset'in SourceLocation'ını döndür.
|
||||
// sourceFile bağlı değilse offset+dosya adı olmadan temel bilgi döndür.
|
||||
// --------------------------------------------------------------------------
|
||||
inline SourceLocation Lexer::getLocation() {
|
||||
return sourceFile.offsetToLocation(getOffset());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// setSourceText: Yeni kaynak kodu yükle ve SourceFile'ı güncelle.
|
||||
// Aynı anda Lexer ve SourceFile'ı hazırlar.
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Lexer::setSourceText(const std::string& path, const std::string& text) {
|
||||
sourceFile.setText(path, text);
|
||||
setText(text);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// setText: Yeni kaynak kodu yükle. input ve size'ı günceller.
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Lexer::setText(std::string text) {
|
||||
input = text;
|
||||
size = text.length();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// skipWhiteSpace: Boşluk, sekme, satırsonu, satırbaşı karakterlerini atla.
|
||||
// Yorum satırlarını atlamaz — bu Tokenizer'ın işi.
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Lexer::skipWhiteSpace() {
|
||||
while (!isEnd()) {
|
||||
switch (getchar()) {
|
||||
case '\r': // carriage return (Windows satırsonu \r\n)
|
||||
case '\n': // line feed (Unix satırsonu)
|
||||
case '\b': // backspace
|
||||
case '\t': // tab
|
||||
case ' ': // boşluk
|
||||
nextChar();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// isNumeric: Mevcut karakter bir rakam mı? (0-9)
|
||||
// Pointer aritmetiği veya ASCII tablosu karşılaştırması yerine basit aralık
|
||||
// kontrolü. Performans: O(1), branchless (modern derleyiciler optimize eder).
|
||||
// --------------------------------------------------------------------------
|
||||
inline bool Lexer::isNumeric() {
|
||||
char c = getchar();
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// readNumeric: Tam bir sayı literal'ı oku.
|
||||
//
|
||||
// Desteklenen formatlar (öncelik sırasıyla):
|
||||
// 1. İşaret: -42, +3 (baştaki isteğe bağlı işaret)
|
||||
// 2. 0x/0X: Hex (0xFF, 0X1A)
|
||||
// 3. 0b/0B: Binary (0b1010)
|
||||
// 4. 0 ile başlayan: Octal (0777) veya Float (0.5)
|
||||
// 5. Ondalık: 42, 3.14
|
||||
// 6. Bilimsel: 1e10, 2.5E-3, 1.0e+5
|
||||
//
|
||||
// Algoritma:
|
||||
// 1. İsteğe bağlı işareti oku (+ veya -)
|
||||
// 2. İlk karakter '0' ise → özel durum (hex/bin/octal/float kontrolü)
|
||||
// 3. Ana döngü: rakamları, hex harflerini (a-f/A-F), nokta (.), epsilon (e/E) oku
|
||||
// 4. Her karakterde taban uygunluğunu kontrol et (örn: octal'da 8-9 geçersiz)
|
||||
// 5. İlk karakter '0' değilse → doğrudan decimal
|
||||
//
|
||||
// Özel durum: "0" takip eden karakter yoksa → tek haneli sayı, base=10.
|
||||
// "0xFF" → hex, "0b10" → binary, "077" → octal, "0.5" → float.
|
||||
//
|
||||
// TODO: Hex float desteği (0x1.ffp10) — C99 standardı
|
||||
// TODO: Sayısal ayraç: 1_000_000 — C++14/Java 7
|
||||
// --------------------------------------------------------------------------
|
||||
inline INumber Lexer::readNumeric() {
|
||||
INumber num;
|
||||
num.start = getLastPosition();
|
||||
num.startLoc = getLocation();
|
||||
|
||||
// --- Adım 1: İsteğe bağlı işaret ---
|
||||
if (getchar() == '-') {
|
||||
nextChar();
|
||||
num.positive = false;
|
||||
} else if (getchar() == '+') {
|
||||
nextChar();
|
||||
num.positive = true;
|
||||
} else {
|
||||
num.positive = true;
|
||||
}
|
||||
|
||||
// --- Adım 2: İlk karakter '0' ise özel format kontrolü ---
|
||||
bool nextDot = false;
|
||||
if (getchar() == '0') {
|
||||
num.token.push_back('0');
|
||||
nextChar();
|
||||
char c = getchar();
|
||||
switch (c) {
|
||||
case 'x': case 'X': // Hex: 0xFF, 0X1A
|
||||
num.token.push_back(c);
|
||||
num.base = 16;
|
||||
nextChar();
|
||||
break;
|
||||
case 'b': case 'B': // Binary: 0b1010
|
||||
num.token.push_back(c);
|
||||
num.base = 2;
|
||||
nextChar();
|
||||
break;
|
||||
case '.': // Float: 0.5, 0.0
|
||||
num.token.push_back(c);
|
||||
num.base = 10;
|
||||
nextDot = true;
|
||||
num.isFloat = true;
|
||||
nextChar();
|
||||
break;
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7':
|
||||
// Octal: 0777 — sonraki karakter octal rakam ise devam et
|
||||
num.base = 8;
|
||||
break;
|
||||
default:
|
||||
// Sadece "0" — takip eden karakter rakam değil.
|
||||
// Hemen dön: base=10 (varsayılan).
|
||||
// BUG FIX (commit 438bc0e): Eskiden bu dalda sıradaki karakter
|
||||
// token'a ekleniyor ve base=8 yapılıyordu. Bu, "0;" durumunda
|
||||
// ';' karakterinin sayıya eklenmesine neden oluyordu.
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
} else {
|
||||
num.base = 10;
|
||||
}
|
||||
|
||||
// --- Adım 3: Ana okuma döngüsü ---
|
||||
// Bu döngü, geçerli tabana uygun tüm karakterleri okur.
|
||||
// Her karakter tipi için taban uygunluğu kontrol edilir:
|
||||
// - 0-1: tüm tabanlar
|
||||
// - 2-7: base >= 8
|
||||
// - 8-9: base >= 10
|
||||
// - a-f/A-F: base >= 16
|
||||
// - . (nokta): sadece ondalık, sadece bir kere
|
||||
// - e/E: sadece ondalık ve hex (hex'te epsilon yok, direkt okunur)
|
||||
while (!isEnd()) {
|
||||
char c = getchar();
|
||||
switch (c) {
|
||||
case '0':
|
||||
case '1':
|
||||
num.token.push_back(c);
|
||||
break;
|
||||
case '2': case '3': case '4': case '5':
|
||||
case '6': case '7':
|
||||
if (num.base >= 8)
|
||||
num.token.push_back(c);
|
||||
else {
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
break;
|
||||
case '8': case '9':
|
||||
if (num.base >= 10)
|
||||
num.token.push_back(c);
|
||||
else {
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
break;
|
||||
case 'a': case 'A': case 'b': case 'B':
|
||||
case 'c': case 'C': case 'd': case 'D':
|
||||
case 'f': case 'F':
|
||||
if (num.base >= 16)
|
||||
num.token.push_back(c);
|
||||
else {
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
// Nokta: Sadece bir kere izin verilir.
|
||||
// .5 gibi başıboş noktalı sayılar için "0." öneki eklenir.
|
||||
if (!nextDot) {
|
||||
if (num.token.empty())
|
||||
num.token += "0.";
|
||||
else
|
||||
num.token.push_back('.');
|
||||
nextDot = true;
|
||||
num.isFloat = true;
|
||||
} else {
|
||||
// İkinci nokta → sayı bitti
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
break;
|
||||
case 'e': case 'E':
|
||||
// Epsilon (bilimsel gösterim):
|
||||
// - Hex tabanda: epsilon DEĞİL, hex hanesi olarak okunur.
|
||||
// - Decimal tabanda: 1e10, 2.5E-3 formatı.
|
||||
if (num.base == 16) {
|
||||
num.token.push_back(c);
|
||||
break;
|
||||
}
|
||||
if (num.base == 10) {
|
||||
num.hasEpsilon = true;
|
||||
num.token.push_back(c);
|
||||
nextChar();
|
||||
c = getchar();
|
||||
// İsteğe bağlı işaret: e+10, E-3
|
||||
if (c == '+' || c == '-') {
|
||||
num.token.push_back(c);
|
||||
nextChar();
|
||||
}
|
||||
// Epsilon sonrası rakamları oku
|
||||
while (!isEnd()) {
|
||||
c = getchar();
|
||||
if (c >= '0' && c <= '9') {
|
||||
num.token.push_back(c);
|
||||
nextChar();
|
||||
} else {
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
default:
|
||||
// Tanınmayan karakter → sayı bitti
|
||||
num.end = getLastPosition();
|
||||
return num;
|
||||
}
|
||||
nextChar();
|
||||
}
|
||||
num.end = getLastPosition();
|
||||
num.endLoc = getLocation();
|
||||
return num;
|
||||
}
|
||||
|
||||
#endif // SAQUT_LEXER
|
||||
|
|
@ -1,45 +1,13 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — Soyut Sözdizim Ağacı (Aggregator)
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/ast.hpp
|
||||
// KATMAN: Katman 3 — Parser'ın ürettiği, IR'nin tükettiği
|
||||
//
|
||||
// Bu dosya bir AGGREGATOR'dür. Tüm AST düğüm sınıflarını tek bir include
|
||||
// ile kullanılabilir yapar.
|
||||
//
|
||||
// AST DÜĞÜM HİYERARŞİSİ:
|
||||
// ASTNode (soyut taban) — ast_node.hpp
|
||||
// ├── ProgramNode : Kök düğüm — ast_decl.hpp
|
||||
// ├── FunctionDeclNode : Fonksiyon tanımı — ast_decl.hpp
|
||||
// ├── StructDeclNode : struct tanımı — ast_decl.hpp
|
||||
// ├── VariableDeclNode : Değişken tanımı — ast_decl.hpp
|
||||
// ├── BlockNode : { ... } bloğu — ast_stmt.hpp
|
||||
// ├── IfStatementNode : if/else — ast_stmt.hpp
|
||||
// ├── WhileStatementNode : while — ast_stmt.hpp
|
||||
// ├── ForStatementNode : for — ast_stmt.hpp
|
||||
// ├── DoWhileStatementNode : do-while — ast_stmt.hpp
|
||||
// ├── ReturnStatementNode : return — ast_stmt.hpp
|
||||
// ├── BreakStatementNode : break — ast_stmt.hpp
|
||||
// ├── ContinueStatementNode : continue — ast_stmt.hpp
|
||||
// ├── ExpressionStatementNode: expression; — ast_stmt.hpp
|
||||
// ├── BinaryExpressionNode : a + b — ast_expr.hpp
|
||||
// ├── LiteralNode : 42, "hello" — ast_expr.hpp
|
||||
// ├── IdentifierNode : değişken ismi — ast_expr.hpp
|
||||
// ├── PostfixNode : a++ — ast_expr.hpp
|
||||
// ├── CallExpressionNode : f(x) — ast_expr.hpp
|
||||
// ├── MemberAccessNode : a.b — ast_expr.hpp
|
||||
// └── IndexExpressionNode : a[i] — ast_expr.hpp
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_AST
|
||||
#define SAQUT_AST
|
||||
|
||||
#include "parser/ast_node.hpp"
|
||||
#include "parser/ast_json.hpp"
|
||||
#include "parser/ast_expr.hpp"
|
||||
#include "parser/ast_stmt.hpp"
|
||||
#include "parser/ast_decl.hpp"
|
||||
#include "parser/nodes/program.hpp"
|
||||
#include "parser/nodes/declarations.hpp"
|
||||
#include "parser/nodes/statements.hpp"
|
||||
#include "parser/nodes/binary_expr.hpp"
|
||||
#include "parser/nodes/literal.hpp"
|
||||
#include "parser/nodes/identifier.hpp"
|
||||
#include "parser/nodes/expressions.hpp"
|
||||
|
||||
#endif // SAQUT_AST
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,143 +0,0 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — AST Deklarasyon Düğümleri
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/ast_decl.hpp
|
||||
// İÇERİK: ProgramNode, FunctionDeclNode, VariableDeclNode, StructDeclNode
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_AST_DECL
|
||||
#define SAQUT_AST_DECL
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "parser/ast_node.hpp"
|
||||
#include "parser/ast_json.hpp"
|
||||
class ProgramNode : public ASTNode {
|
||||
public:
|
||||
ProgramNode() { kind = ASTKind::Program; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "Program\n";
|
||||
for (auto* c : getChildren()) c->log(indent + 2);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"Program\",\n"
|
||||
<< in << " \"children\": [\n"
|
||||
<< childrenToJson(this, depth + 3)
|
||||
<< in << " ]\n"
|
||||
<< in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class FunctionDeclNode : public ASTNode {
|
||||
public:
|
||||
std::string name;
|
||||
std::string returnType;
|
||||
|
||||
FunctionDeclNode() { kind = ASTKind::FunctionDecl; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent)
|
||||
<< "FunctionDecl " << returnType << " " << name << "()\n";
|
||||
for (auto* c : getChildren()) c->log(indent + 2);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"FunctionDecl\",\n"
|
||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
||||
<< in << " \"returnType\": \"" << jsonEscape(returnType) << "\",\n"
|
||||
<< in << " \"location\": " << loc.toJson() << ",\n"
|
||||
<< in << " \"children\": [\n"
|
||||
<< childrenToJson(this, depth + 3)
|
||||
<< in << " ]\n"
|
||||
<< in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class VariableDeclNode : public ASTNode {
|
||||
public:
|
||||
std::string varType;
|
||||
std::string name;
|
||||
ASTNode* initExpr = nullptr;
|
||||
|
||||
VariableDeclNode() { kind = ASTKind::VariableDecl; }
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"VariableDecl\",\n"
|
||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
||||
<< in << " \"varType\": \"" << jsonEscape(varType) << "\",\n"
|
||||
<< in << " \"location\": " << loc.toJson() << "";
|
||||
if (initExpr) {
|
||||
ss << ",\n" << in << " \"initExpr\":\n"
|
||||
<< initExpr->toJson(depth + 2);
|
||||
}
|
||||
// Çoklu değişken bildirimindeki kardeşler (int a, b, c;)
|
||||
if (!getChildren().empty()) {
|
||||
ss << ",\n" << in << " \"declarators\": [\n";
|
||||
for (size_t i = 0; i < getChildren().size(); i++) {
|
||||
ss << ((VariableDeclNode*)getChildren()[i])->toJson(depth + 2);
|
||||
if (i + 1 < getChildren().size()) ss << ",";
|
||||
ss << "\n";
|
||||
}
|
||||
ss << in << " ]";
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent)
|
||||
<< "VariableDecl " << varType << " " << name;
|
||||
if (initExpr) {
|
||||
std::cout << " =\n";
|
||||
initExpr->log(indent + 4);
|
||||
} else {
|
||||
std::cout << "\n";
|
||||
}
|
||||
// Kardeş değişkenleri de logla
|
||||
for (auto* child : getChildren()) {
|
||||
child->log(indent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class StructDeclNode : public ASTNode {
|
||||
public:
|
||||
std::string name;
|
||||
|
||||
StructDeclNode() { kind = ASTKind::StructDecl; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "StructDecl " << name << "\n";
|
||||
for (auto* c : getChildren()) c->log(indent + 2);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"StructDecl\",\n"
|
||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
||||
<< in << " \"children\": [\n"
|
||||
<< childrenToJson(this, depth + 3)
|
||||
<< in << " ]\n"
|
||||
<< in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
#endif // SAQUT_AST_DECL
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — AST İfade Düğümleri
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/ast_expr.hpp
|
||||
// İÇERİK: BinaryExpr, Literal, Identifier, Postfix,
|
||||
// CallExpression, MemberAccess, IndexExpression
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_AST_EXPR
|
||||
#define SAQUT_AST_EXPR
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "parser/ast_node.hpp"
|
||||
#include "parser/ast_json.hpp"
|
||||
class BinaryExpressionNode : public ASTNode {
|
||||
public:
|
||||
TokenType Operator;
|
||||
ASTNode* Left = nullptr;
|
||||
ASTNode* Right = nullptr;
|
||||
|
||||
BinaryExpressionNode() { kind = ASTKind::BinaryExpression; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
auto it = OPERATOR_MAP_STRREV.find(Operator);
|
||||
std::string sym = (it != OPERATOR_MAP_STRREV.end()) ? std::string(it->second) : "?";
|
||||
std::string val;
|
||||
auto it2 = OPERATOR_MAP_REV.find(Operator);
|
||||
if (it2 != OPERATOR_MAP_REV.end()) val = std::string(it2->second);
|
||||
|
||||
std::cout << padRight("", indent) << "BinaryExpr " << sym
|
||||
<< " (" << val << ")\n";
|
||||
if (Right) Right->log(indent + 2);
|
||||
if (Left) Left->log(indent + 2);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::string opSym = "?";
|
||||
auto it = OPERATOR_MAP_REV.find(Operator);
|
||||
if (it != OPERATOR_MAP_REV.end()) opSym = std::string(it->second);
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"BinaryExpression\",\n"
|
||||
<< in << " \"operator\": \"" << jsonEscape(opSym) << "\",\n"
|
||||
<< in << " \"location\": " << loc.toJson() << "";
|
||||
if (Left) {
|
||||
ss << ",\n" << in << " \"left\":\n"
|
||||
<< Left->toJson(depth + 2);
|
||||
}
|
||||
if (Right) {
|
||||
ss << ",\n" << in << " \"right\":\n"
|
||||
<< Right->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
// LiteralType enum'u ve literalTypeToString ast_node.hpp'de tanımlıdır.
|
||||
|
||||
class LiteralNode : public ASTNode {
|
||||
public:
|
||||
Token* lexerToken = nullptr;
|
||||
ParserToken parserToken;
|
||||
|
||||
LiteralType literalType = LiteralType::INTEGER;
|
||||
int literalBase = 10; // 10, 16, 8, 2 (sadece INTEGER/FLOAT için)
|
||||
bool isFloatValue = false; // Ondalıklı mı? (sadece INTEGER/FLOAT için)
|
||||
|
||||
LiteralNode() { kind = ASTKind::Literal; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent)
|
||||
<< "Literal {" << parserToken.token->token << "} "
|
||||
<< literalTypeToString(literalType);
|
||||
if (literalType == LiteralType::INTEGER && literalBase != 10)
|
||||
std::cout << " (base " << literalBase << ")";
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::string val = parserToken.token ? parserToken.token->token : "?";
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"Literal\",\n"
|
||||
<< in << " \"literalType\": \"" << literalTypeToString(literalType) << "\",\n"
|
||||
<< in << " \"value\": \"" << jsonEscape(val) << "\"";
|
||||
if (literalType == LiteralType::INTEGER && literalBase != 10) {
|
||||
ss << ",\n" << in << " \"base\": " << literalBase;
|
||||
}
|
||||
if (literalType == LiteralType::FLOAT) {
|
||||
ss << ",\n" << in << " \"isFloat\": true";
|
||||
}
|
||||
ss << ",\n" << in << " \"location\": " << loc.toJson() << "\n"
|
||||
<< in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class IdentifierNode : public ASTNode {
|
||||
public:
|
||||
Token* lexerToken = nullptr;
|
||||
ParserToken parserToken;
|
||||
|
||||
IdentifierNode() { kind = ASTKind::Identifier; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent)
|
||||
<< "Identifier {" << parserToken.token->token << "}\n";
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::string name = parserToken.token ? parserToken.token->token : "?";
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"Identifier\",\n"
|
||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
||||
<< in << " \"location\": " << loc.toJson() << "\n"
|
||||
<< in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class PostfixNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* operand = nullptr;
|
||||
TokenType Operator;
|
||||
|
||||
PostfixNode() { kind = ASTKind::Postfix; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
auto it = OPERATOR_MAP_STRREV.find(Operator);
|
||||
std::string sym = (it != OPERATOR_MAP_STRREV.end()) ? std::string(it->second) : "?";
|
||||
std::cout << padRight("", indent) << "Postfix " << sym;
|
||||
auto it2 = OPERATOR_MAP_REV.find(Operator);
|
||||
if (it2 != OPERATOR_MAP_REV.end())
|
||||
std::cout << " (" << it2->second << ")";
|
||||
std::cout << "\n";
|
||||
if (operand) operand->log(indent + 2);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::string opSym = "?";
|
||||
auto it = OPERATOR_MAP_REV.find(Operator);
|
||||
if (it != OPERATOR_MAP_REV.end()) opSym = std::string(it->second);
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"Postfix\",\n"
|
||||
<< in << " \"operator\": \"" << jsonEscape(opSym) << "\"";
|
||||
if (operand) {
|
||||
ss << ",\n" << in << " \"operand\":\n"
|
||||
<< operand->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class CallExpressionNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* callee = nullptr;
|
||||
std::vector<ASTNode*> arguments;
|
||||
|
||||
CallExpressionNode() { kind = ASTKind::Call; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "Call\n";
|
||||
if (callee) {
|
||||
std::cout << padRight("", indent + 2) << "Callee:\n";
|
||||
callee->log(indent + 4);
|
||||
}
|
||||
std::cout << padRight("", indent + 2) << "Args (" << arguments.size() << "):\n";
|
||||
for (auto* a : arguments) a->log(indent + 4);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"Call\"";
|
||||
if (callee) {
|
||||
ss << ",\n" << in << " \"callee\":\n"
|
||||
<< callee->toJson(depth + 2);
|
||||
}
|
||||
ss << ",\n" << in << " \"arguments\": [\n";
|
||||
for (size_t i = 0; i < arguments.size(); i++) {
|
||||
ss << arguments[i]->toJson(depth + 3);
|
||||
if (i + 1 < arguments.size()) ss << ",";
|
||||
ss << "\n";
|
||||
}
|
||||
ss << in << " ]\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// MemberAccessNode — Üye Erişimi a.b veya a->b
|
||||
// ============================================================================
|
||||
|
||||
|
||||
class MemberAccessNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* object = nullptr;
|
||||
std::string member;
|
||||
bool arrow = false;
|
||||
|
||||
MemberAccessNode() { kind = ASTKind::MemberAccess; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "MemberAccess "
|
||||
<< (arrow ? "->" : ".") << " " << member << "\n";
|
||||
if (object) object->log(indent + 2);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"MemberAccess\",\n"
|
||||
<< in << " \"member\": \"" << jsonEscape(member) << "\",\n"
|
||||
<< in << " \"arrow\": " << (arrow ? "true" : "false");
|
||||
if (object) {
|
||||
ss << ",\n" << in << " \"object\":\n"
|
||||
<< object->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// IndexExpressionNode — Dizi Erişimi a[i]
|
||||
// ============================================================================
|
||||
|
||||
|
||||
class IndexExpressionNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* object = nullptr;
|
||||
ASTNode* index = nullptr;
|
||||
|
||||
IndexExpressionNode() { kind = ASTKind::IndexExpression; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "IndexExpression\n";
|
||||
if (object) {
|
||||
std::cout << padRight("", indent + 2) << "Object:\n";
|
||||
object->log(indent + 4);
|
||||
}
|
||||
if (index) {
|
||||
std::cout << padRight("", indent + 2) << "Index:\n";
|
||||
index->log(indent + 4);
|
||||
}
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"IndexExpression\"";
|
||||
if (object) {
|
||||
ss << ",\n" << in << " \"object\":\n"
|
||||
<< object->toJson(depth + 2);
|
||||
}
|
||||
if (index) {
|
||||
ss << ",\n" << in << " \"index\":\n"
|
||||
<< index->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// StructDeclNode — struct Tanımı
|
||||
// ============================================================================
|
||||
|
||||
|
||||
#endif // SAQUT_AST_EXPR
|
||||
|
|
@ -3,7 +3,8 @@
|
|||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/ast_json.hpp
|
||||
// KATMAN: AST — Sadece AST düğümlerinin toJson() metotları için
|
||||
// KATMAN: Katman 3 — Parser (AST JSON serileştirme)
|
||||
// AMAÇ: AST düğümlerinin toJson() metotlarında kullanılan builder pattern
|
||||
// BAĞIMLI: Yok (sadece <string>, <sstream>)
|
||||
//
|
||||
// AMAÇ:
|
||||
|
|
@ -17,6 +18,15 @@
|
|||
// obj.add("location", loc.toJson()); // ham JSON gömme
|
||||
// return obj.str();
|
||||
//
|
||||
// TASARIM KARARLARI:
|
||||
// 1. Builder pattern: add() çağrıları zincirlenemez ama okunabilirlik kazanır.
|
||||
// Zincirleme için: return obj.add("a",1).add("b",2).str() — tercih edilmedi.
|
||||
// 2. addRaw(): Önceden formatlanmış JSON (alt düğüm çıktısı) gömmek için.
|
||||
// 3. addArray(): Callback ile dizi oluşturma — C++ lambda'ları sayesinde temiz.
|
||||
// 4. addIfNotEmpty/addIfNot: Koşullu alanlar — null alanları JSON'da göstermemek için.
|
||||
// JSON çıktısını temiz tutar.
|
||||
// 5. JSON_INDENT = 2: Standart JSON girinti (4 değil, 2 okunabilir).
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_AST_JSON
|
||||
|
|
@ -25,7 +35,11 @@
|
|||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
// Girinti sabiti (tools.hpp'deki jsonIndent ile uyumlu)
|
||||
// ============================================================================
|
||||
// JSON_INDENT — JSON girinti miktarı (boşluk sayısı)
|
||||
// ============================================================================
|
||||
// tools.hpp'deki jsonIndent() ile uyumlu olmalıdır.
|
||||
// Her seviyede 2 boşluk içe kaydırılır.
|
||||
#define JSON_INDENT 2
|
||||
|
||||
// jsonEscape ve jsonIndent tools.hpp'de tanımlıdır.
|
||||
|
|
@ -34,6 +48,10 @@
|
|||
// JsonObject — JSON Nesne Builder
|
||||
// ============================================================================
|
||||
//
|
||||
// AST düğümlerini JSON formatına dönüştürmek için kullanılır.
|
||||
// Her çağrıda yeni bir JsonObject oluşturulur, alanlar eklenir ve str() ile
|
||||
// JSON stringi alınır.
|
||||
//
|
||||
// KULLANIM:
|
||||
// JsonObject obj(depth);
|
||||
// obj.add("kind", "FunctionDecl");
|
||||
|
|
@ -46,10 +64,21 @@
|
|||
// });
|
||||
// return obj.str();
|
||||
//
|
||||
// ÖRNEK ÇIKTI (depth=0):
|
||||
// {
|
||||
// "kind": "FunctionDecl",
|
||||
// "name": "main",
|
||||
// "returnType": "int",
|
||||
// "children": [ ... ]
|
||||
// }
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
class JsonObject {
|
||||
public:
|
||||
// JsonObject — Yapıcı
|
||||
// PARAMETRE: depth — JSON girinti seviyesi (0 = en dış)
|
||||
// YAN ETKİ: m_ss'e açılış süslü parantezi yazar
|
||||
JsonObject(int depth)
|
||||
: m_indent(jsonIndent(depth)),
|
||||
m_indentInner(jsonIndent(depth + 1))
|
||||
|
|
@ -57,44 +86,89 @@ public:
|
|||
m_ss << m_indent << "{\n";
|
||||
}
|
||||
|
||||
// String alan ekle (değer tırnak içinde yazılır)
|
||||
// add() — String alan ekle
|
||||
// PARAMETRELER:
|
||||
// key — JSON anahtarı (tırnak içinde yazılır)
|
||||
// value — string değer (otomatik tırnaklanır ve escape edilir)
|
||||
// YAN ETKİ: m_hasFields true olur
|
||||
// ÖRN: obj.add("name", "main") → "name": "main"
|
||||
void add(const std::string& key, const std::string& value) {
|
||||
addRaw(key, "\"" + jsonEscape(value) + "\"");
|
||||
}
|
||||
|
||||
// Sayısal alan ekle (değer olduğu gibi yazılır)
|
||||
// add() — Sayısal alan ekle
|
||||
// PARAMETRELER:
|
||||
// key — JSON anahtarı
|
||||
// value — tamsayı değer (tırnaklanmaz, olduğu gibi yazılır)
|
||||
// ÖRN: obj.add("line", 42) → "line": 42
|
||||
void add(const std::string& key, int value) {
|
||||
addRaw(key, std::to_string(value));
|
||||
}
|
||||
|
||||
// Boolean alan ekle
|
||||
// add() — Boolean alan ekle
|
||||
// PARAMETRELER:
|
||||
// key — JSON anahtarı
|
||||
// value — true/false
|
||||
// ÖRN: obj.add("isPublic", true) → "isPublic": true
|
||||
void add(const std::string& key, bool value) {
|
||||
addRaw(key, value ? "true" : "false");
|
||||
}
|
||||
|
||||
// Ham JSON değeri ekle (önceden formatlanmış, tırnaklanmamış)
|
||||
// addRaw() — Ham JSON değeri ekle (önceden formatlanmış)
|
||||
// PARAMETRELER:
|
||||
// key — JSON anahtarı
|
||||
// jsonValue — önceden JSON'a çevrilmiş değer (tırnaklanmaz!)
|
||||
// KULLANIM: Alt düğüm toJson() çıktısını gömmek için.
|
||||
// addRaw("location", loc.toJson());
|
||||
void addRaw(const std::string& key, const std::string& jsonValue) {
|
||||
if (m_hasFields) m_ss << ",\n";
|
||||
m_ss << m_indentInner << "\"" << jsonEscape(key) << "\": " << jsonValue;
|
||||
m_hasFields = true;
|
||||
}
|
||||
|
||||
// Alt nesne ekle (bir alt seviyede JSON nesnesi)
|
||||
// addNested() — Alt nesne ekle (addRaw alias)
|
||||
// PARAMETRELER: addRaw ile aynı
|
||||
// KULLANIM: addRaw ile aynı. Sadece okunabilirlik için.
|
||||
void addNested(const std::string& key, const std::string& nestedJson) {
|
||||
addRaw(key, nestedJson);
|
||||
}
|
||||
|
||||
// Koşullu string alan (value boş değilse ekle)
|
||||
// addIfNotEmpty() — Koşullu string alan
|
||||
// PARAMETRELER:
|
||||
// key — JSON anahtarı
|
||||
// value — string değer (sadece boş DEĞİLSE eklenir)
|
||||
// KULLANIM: Opsiyonel alanlar için. JSON çıktısını temiz tutar.
|
||||
// obj.addIfNotEmpty("defaultValue", defaultVal);
|
||||
void addIfNotEmpty(const std::string& key, const std::string& value) {
|
||||
if (!value.empty()) add(key, value);
|
||||
}
|
||||
|
||||
// Koşullu sayı alan (value varsayılandan farklıysa ekle)
|
||||
// addIfNot() — Koşullu sayı alan
|
||||
// PARAMETRELER:
|
||||
// key — JSON anahtarı
|
||||
// value — mevcut değer
|
||||
// defaultValue — varsayılan değer
|
||||
// EKLEME KOŞULU: value != defaultValue
|
||||
// KULLANIM: Varsayılan değerler JSON'da tekrarlanmaz.
|
||||
// obj.addIfNot("precedence", 0, 14);
|
||||
void addIfNot(const std::string& key, int value, int defaultValue) {
|
||||
if (value != defaultValue) add(key, value);
|
||||
}
|
||||
|
||||
// Dizi alanı (callback içinde addItem çağrılır)
|
||||
// addArray() — Dizi alanı (callback ile)
|
||||
// PARAMETRELER:
|
||||
// key — JSON anahtarı
|
||||
// callback — dizi elemanlarını addItem ile ekleyen lambda/fonksiyon
|
||||
// KULLANIM:
|
||||
// obj.addArray("children", [&] {
|
||||
// for (auto* child : children)
|
||||
// obj.addItem(child->toJson(depth + 2));
|
||||
// });
|
||||
// ÖRNEK ÇIKTI:
|
||||
// "children": [
|
||||
// { "kind": "Literal", ... },
|
||||
// { "kind": "Identifier", ... }
|
||||
// ]
|
||||
template<typename Fn>
|
||||
void addArray(const std::string& key, Fn callback) {
|
||||
if (m_hasFields) m_ss << ",\n";
|
||||
|
|
@ -106,7 +180,10 @@ public:
|
|||
m_hasFields = true;
|
||||
}
|
||||
|
||||
// Diziye eleman ekle (addArray callback'i içinde kullanılır)
|
||||
// addItem() — Diziye eleman ekle
|
||||
// PARAMETRE: itemJson — JSON formatında dizi elemanı
|
||||
// KULLANIM: Sadece addArray callback'i içinde kullanılır.
|
||||
// YAN ETKİ: m_hasArrayItem true olur (virgül kontrolü için)
|
||||
void addItem(const std::string& itemJson) {
|
||||
if (m_hasArrayItem) m_ss << ",";
|
||||
// Öğeler m_indentInner'in bir seviye altında (depth + 2)
|
||||
|
|
@ -116,19 +193,36 @@ public:
|
|||
m_hasArrayItem = true;
|
||||
}
|
||||
|
||||
// Nesneyi kapat ve string olarak döndür
|
||||
// str() — JSON nesnesini kapat ve string olarak döndür
|
||||
// DÖNÜŞ: Tam JSON stringi ({"key": "value", ...})
|
||||
// YAN ETKİ: Kapanış süslü parantezini ekler.
|
||||
// KULLANIM:
|
||||
// JsonObject obj(depth);
|
||||
// obj.add("kind", "FunctionDecl");
|
||||
// return obj.str();
|
||||
std::string str() {
|
||||
m_ss << "\n" << m_indent << "}";
|
||||
return m_ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostringstream m_ss;
|
||||
std::string m_indent; // Bu nesnenin girintisi
|
||||
std::string m_indentInner; // Bir alt seviye girinti
|
||||
bool m_hasFields = false;
|
||||
int m_arrayDepth = 0; // İç içe dizi seviyesi
|
||||
bool m_hasArrayItem = false;
|
||||
/* ====== Builder State ====== */
|
||||
std::ostringstream m_ss; // JSON çıktısının biriktirildiği string stream
|
||||
|
||||
std::string m_indent; // Bu nesnenin girinti seviyesi (depth * 2 boşluk)
|
||||
// Örn: depth=0 → "", depth=1 → " "
|
||||
|
||||
std::string m_indentInner; // Bir alt seviye girinti ((depth+1) * 2 boşluk)
|
||||
// Örn: depth=0 → " ", depth=1 → " "
|
||||
|
||||
bool m_hasFields = false; // Alan eklendi mi? (virgül kontrolü için)
|
||||
// true ise bir sonraki alandan önce virgül + newline
|
||||
|
||||
int m_arrayDepth = 0; // İç içe dizi seviyesi (şu anda kullanılmıyor,
|
||||
// ileride çok boyutlu diziler için)
|
||||
|
||||
bool m_hasArrayItem = false; // Diziye eleman eklendi mi? (virgül kontrolü)
|
||||
// true ise bir sonraki elemandan önce virgül
|
||||
};
|
||||
|
||||
#endif // SAQUT_AST_JSON
|
||||
|
|
|
|||
|
|
@ -3,12 +3,23 @@
|
|||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/ast_node.hpp
|
||||
// KATMAN: Katman 3 — Parser
|
||||
// BAĞIMLI: core/location.hpp, parser/token.hpp, tools.hpp
|
||||
// KATMAN: Katman 3 — Parser (Ayrıştırıcı)
|
||||
// AMAÇ: Tüm AST düğümlerinin taban sınıfını ve temel enum'ları tanımlamak
|
||||
//
|
||||
// Bu dosya: ASTNode taban sınıfını, ASTKind enum'unu, LiteralType enum'unu
|
||||
// ve çocuk düğümleri JSON olarak yazdırmak için childrenToJson yardımcısını
|
||||
// içerir. Diğer tüm düğüm sınıfları bu dosyayı include eder.
|
||||
// BAĞIMLILIKLAR:
|
||||
// - core/location.hpp: Kaynak kod konum bilgisi (SourceLocation)
|
||||
// - parser/token.hpp: Token tipleri (TokenType, ParserToken)
|
||||
// - tools.hpp: Yardımcı fonksiyonlar (jsonIndent vb.)
|
||||
//
|
||||
// MİMARİ KARARLAR:
|
||||
// 1. ASTNode, tüm düğümlerin ortak davranışını (log, toJson, children)
|
||||
// tek bir yerde tanımlar. NVI (Non-Virtual Interface) pattern'i.
|
||||
// 2. virtual log() ve toJson() — her düğüm kendi çıktısını kendisi üretir.
|
||||
// 3. parent pointer — AST'de yukarı doğru gezinme (ör: sembol çözümleme).
|
||||
// 4. children vector — aşağı doğru gezinme (ör: tüm düğümleri ziyaret).
|
||||
// 5. ASTKind enum — switch/case ile tip kontrolü (dynamic_cast yerine).
|
||||
// Performans: dynamic_cast < switch/case < virtual method çağrısı
|
||||
// Ama switch/case ile yeni tip eklemek derleyici uyarısı verir (eksik case).
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
|
|
@ -26,43 +37,112 @@
|
|||
// ============================================================================
|
||||
// ASTKind — Düğüm Tipi Enum
|
||||
// ============================================================================
|
||||
//
|
||||
// Tüm AST düğüm tiplerini tanımlar. Her düğüm sınıfı bu enum'dan bir değer
|
||||
// alır. enum class olması sayesinde isim çakışması olmaz (ASTKind::Program).
|
||||
//
|
||||
// NEDEN enum class, neden inheritance'daki typeid kullanılmıyor?
|
||||
// - typeid().name() derleyiciye bağlıdır (g++: "4Program", MSVC: "class Program").
|
||||
// - enum class her derleyicide aynıdır, string dönüşümü kolaydır.
|
||||
// - static_cast<uint16_t> ile serileştirilebilir.
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
enum class ASTKind {
|
||||
Program, // Kök düğüm
|
||||
FunctionDecl, // Fonksiyon tanımı
|
||||
Block, // { } bloğu
|
||||
VariableDecl, // Değişken tanımı
|
||||
BinaryExpression, // İkili işlem (a + b)
|
||||
UnaryExpression, // Tekli işlem (-a, !a)
|
||||
Literal, // Sabit değer
|
||||
Identifier, // İsim referansı
|
||||
Postfix, // Son ek (a++)
|
||||
IfStatement, // if/else
|
||||
ForStatement, // for
|
||||
WhileStatement, // while
|
||||
DoWhileStatement, // do-while
|
||||
ReturnStatement, // return
|
||||
BreakStatement, // break
|
||||
ContinueStatement, // continue
|
||||
ExpressionStatement, // ifade + ;
|
||||
Call, // Fonksiyon çağrısı f(args)
|
||||
MemberAccess, // Üye erişimi a.b, a->b
|
||||
IndexExpression, // Dizi erişimi a[i]
|
||||
StructDecl, // struct tanımı
|
||||
/* ====== En üst seviye ====== */
|
||||
Program, // Kök düğüm — tüm programı kapsar.
|
||||
// İçindeki children: FunctionDecl, StructDecl, VariableDecl.
|
||||
// Tüm .cpp/.sqt dosyası tek bir Program düğümüdür.
|
||||
|
||||
/* ====== Tanımlar (Declarations) ====== */
|
||||
FunctionDecl, // Fonksiyon tanımı.
|
||||
// children: [returnType?], [name], [params...], [body: Block]
|
||||
// Örn: int main() { ... }
|
||||
StructDecl, // struct tanımı.
|
||||
// children: [name], [members: VariableDecl...]
|
||||
// Örn: struct Point { int x; int y; };
|
||||
VariableDecl, // Değişken tanımı.
|
||||
// children: [type?], [name], [initializer?]
|
||||
// Örn: int x = 5; veya string name;
|
||||
|
||||
/* ====== Kontrol Akışı (Statements) ====== */
|
||||
Block, // { } bloğu — birleşik ifade.
|
||||
// children: [statements...]
|
||||
// Kapsam (scope) oluşturur. Yerel değişkenler burada tanımlanır.
|
||||
IfStatement, // if (koşul) gövde [else gövde].
|
||||
// children: [condition], [thenBranch], [elseBranch?]
|
||||
ForStatement, // for (init; koşul; artım) gövde.
|
||||
// children: [init?], [condition?], [increment?], [body]
|
||||
WhileStatement, // while (koşul) gövde.
|
||||
// children: [condition], [body]
|
||||
DoWhileStatement, // do gövde while (koşul);
|
||||
// children: [body], [condition]
|
||||
ReturnStatement, // return [ifade?];
|
||||
// children: [value?]
|
||||
BreakStatement, // break;
|
||||
// children: yok. Sadece döngü/switch içinde geçerli.
|
||||
ContinueStatement, // continue;
|
||||
// children: yok. Sadece döngü içinde geçerli.
|
||||
ExpressionStatement, // ifade + noktalı virgül (;)
|
||||
// children: [expression]
|
||||
// Örn: x = 5; veya foo();
|
||||
|
||||
/* ====== İfadeler (Expressions) ====== */
|
||||
BinaryExpression, // İkili işlem: sol OP sağ.
|
||||
// children: [left], [right]
|
||||
// OP bilgisi: exprType alanında saklanır.
|
||||
UnaryExpression, // Tekli işlem: OP operand.
|
||||
// children: [operand]
|
||||
// prefix (++x) veya postfix (x++) olabilir.
|
||||
Literal, // Sabit değer: 42, 3.14, "hello", true, null.
|
||||
// children: yok. Değer düğümün kendi alanında.
|
||||
Identifier, // İsim referansı: x, PI, main.
|
||||
// children: yok. İsim string olarak saklanır.
|
||||
Postfix, // Postfix işlem: operand++.
|
||||
// children: [operand]
|
||||
Call, // Fonksiyon/metot çağrısı: f(args).
|
||||
// children: [callee], [args...]
|
||||
MemberAccess, // Üye erişimi: a.b veya a->b.
|
||||
// children: [object], [member]
|
||||
IndexExpression, // Dizi/indeks erişimi: a[i].
|
||||
// children: [object], [index]
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// LiteralType — Sabit Değer Alt Tipleri
|
||||
// ============================================================================
|
||||
//
|
||||
// Literal düğümünün hangi türde bir sabit değer taşıdığını belirler.
|
||||
// uint8_t tabanlı — 256 farklı literal tipi yeterli.
|
||||
//
|
||||
// KULLANIM:
|
||||
// Literal düğümü oluşturulurken tip belirtilir:
|
||||
// Literal lit(LiteralType::INTEGER, "42");
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
enum class LiteralType : uint8_t {
|
||||
INTEGER, // Tamsayı (decimal, hex, octal, binary)
|
||||
FLOAT, // Ondalıklı sayı (3.14, 1e-5)
|
||||
STRING, // Metin ("hello")
|
||||
BOOLEAN, // true / false
|
||||
BOŞ // null
|
||||
INTEGER, // Tamsayı sabiti: 42, 0xFF, 0b1010, 0777
|
||||
// Decimal, hexadecimal (0x), octal (0), binary (0b) desteklenir.
|
||||
// Tokenizer NumberToken ile iletilir.
|
||||
FLOAT, // Ondalıklı sayı: 3.14, 1e-5, 2.0f
|
||||
// Nokta veya üs (e/E) içeren sayılar.
|
||||
STRING, // Metin sabiti: "merhaba dünya"
|
||||
// Çift tırnak içinde. Kaçış dizileri (\n, \t, \") desteklenir.
|
||||
BOOLEAN, // Mantıksal değer: true / false
|
||||
// KW_TRUE veya KW_FALSE token'ından gelir.
|
||||
BOŞ // null sabiti (Türkçe "boş").
|
||||
// KW_NULL token'ından gelir. Nesne/referans türleri için kullanılır.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// literalTypeToString — LiteralType'ı string'e çevir (log için)
|
||||
// ============================================================================
|
||||
//
|
||||
// PARAMETRE: t — LiteralType enum değeri
|
||||
// DÖNÜŞ: const char* — insan tarafından okunabilir string
|
||||
// KARMAŞIKLIK: O(1) — switch/case (derleyici jump table üretir)
|
||||
//
|
||||
inline const char* literalTypeToString(LiteralType t) {
|
||||
switch (t) {
|
||||
case LiteralType::INTEGER: return "integer";
|
||||
|
|
@ -79,53 +159,119 @@ inline const char* literalTypeToString(LiteralType t) {
|
|||
// ============================================================================
|
||||
//
|
||||
// Tüm AST düğümleri bu sınıftan türetilir. Her düğüm:
|
||||
// - kind: Tipini bilir (ASTKind enum)
|
||||
// - parent: Ebeveynine işaret eder
|
||||
// - loc: Kaynak koddaki konumunu bilir
|
||||
// - log(): Konsola yazdırılabilir
|
||||
// - toJson: JSON olarak serileştirilebilir
|
||||
// - kind: ASTKind enum — tipini bilir (switch/case için)
|
||||
// - parent: Ebeveyn düğüme işaretçi (ağaçta yukarı gezinme)
|
||||
// - loc: Kaynak koddaki satır/sütun konumu (hata mesajları için)
|
||||
// - children: Alt düğümler (ağaçta aşağı gezinme)
|
||||
// - log(): Konsola hiyerarşik yazdırma
|
||||
// - toJson(): JSON formatında serileştirme
|
||||
//
|
||||
// KALITIM:
|
||||
// Program : ASTNode — Kök düğüm
|
||||
// FunctionDecl : ASTNode — Fonksiyon tanımı
|
||||
// BinaryExpression : ASTNode — İkili işlem
|
||||
// ... (her düğüm tipi ayrı sınıf)
|
||||
//
|
||||
// BELLEK YÖNETİMİ:
|
||||
// Düğümler new ile oluşturulur, delete ile yok edilir.
|
||||
// Sahiplik: Parser oluşturur, çağıran (main/CLI) yok eder.
|
||||
// TODO(Büyük yeniden düzenleme): std::unique_ptr ile RAII.
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
class ASTNode {
|
||||
public:
|
||||
ASTKind kind;
|
||||
ASTNode* parent = nullptr;
|
||||
SourceLocation loc;
|
||||
/* ====== Her düğümün tipi ====== */
|
||||
ASTKind kind; // Düğüm tipi (Program, FunctionDecl, ...)
|
||||
// switch(kind) ile tip kontrolü.
|
||||
// Set edilir ve bir daha değişmez.
|
||||
|
||||
/* ====== Ağaç bağlantıları ====== */
|
||||
ASTNode* parent = nullptr; // Ebeveyn düğüm pointerı.
|
||||
// addChild() tarafından otomatik set edilir.
|
||||
// Kullanım: semantic analizde kapsam bulma.
|
||||
// Örn: değişkenin tanımlandığı fonksiyonu bulmak
|
||||
// için parent->parent->... şeklinde yukarı çıkılır.
|
||||
|
||||
/* ====== Kaynak konumu ====== */
|
||||
SourceLocation loc; // Tokenizer'dan gelen satır/sütun bilgisi.
|
||||
// Hata mesajlarında: "satır 5, sütun 12"
|
||||
// TODO: Şu anda tüm düğümlerde dolu değil.
|
||||
|
||||
/* ====== Sanal Metotlar ====== */
|
||||
|
||||
// log() — Düğümü ve alt düğümlerini konsola yazdırır.
|
||||
// PARAMETRE: indent — girinti seviyesi (her seviyede 2 boşluk artar)
|
||||
// KULLANIM: ast->log(0); // tüm ağacı yazdır
|
||||
// KARMAŞIKLIK: O(n) — tüm alt ağacı dolaşır
|
||||
virtual void log(int indent = 0) {
|
||||
(void)indent;
|
||||
std::cout << "<Unknown>\n";
|
||||
}
|
||||
|
||||
// toJson() — Düğümü ve alt düğümlerini JSON formatında döndürür.
|
||||
// PARAMETRE: indent — JSON girinti seviyesi
|
||||
// DÖNÜŞ: JSON stringi
|
||||
// KULLANIM: std::string json = ast->toJson(0);
|
||||
// KARMAŞIKLIK: O(n) — tüm alt ağacı dolaşır, string birleştirme maliyeti
|
||||
virtual std::string toJson(int indent = 0) {
|
||||
(void)indent;
|
||||
return "{\"kind\":\"Unknown\"}";
|
||||
}
|
||||
|
||||
/* ====== Yardımcı Metotlar ====== */
|
||||
|
||||
// addChild() — Alt düğüm ekler ve parent pointer'ını set eder.
|
||||
// PARAMETRE: child — eklenecek alt düğüm (nullptr olmamalı)
|
||||
// YAN ETKİ: child->parent = this (otomatik)
|
||||
// KARMAŞIKLIK: O(1) amortize — vector push_back
|
||||
void addChild(ASTNode* child) {
|
||||
children.push_back(child);
|
||||
child->parent = this;
|
||||
}
|
||||
|
||||
// getChildren() — Alt düğüm vektörüne erişim.
|
||||
// DÖNÜŞ: std::vector<ASTNode*>& — çocuk düğümler listesi
|
||||
// KARMAŞIKLIK: O(1) — referans döndürür
|
||||
std::vector<ASTNode*>& getChildren() { return children; }
|
||||
|
||||
// ~ASTNode() — Sanal yıkıcı (polimorfik silme için)
|
||||
// delete ASTNode* yapıldığında doğru alt sınıf yıkıcısı çağrılır.
|
||||
// Bu olmazsa türetilmiş sınıfların kaynakları sızdırılır.
|
||||
virtual ~ASTNode() = default;
|
||||
|
||||
protected:
|
||||
// children — Alt düğümlerin vektörü.
|
||||
// protected: doğrudan erişim yerine addChild/getChildren kullanılır.
|
||||
// Türetilmiş sınıflar erişebilir (ör: log() içinde çocukları gezme).
|
||||
std::vector<ASTNode*> children;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// childrenToJson — Düğümün çocuklarını JSON array olarak yaz
|
||||
// ============================================================================
|
||||
|
||||
//
|
||||
// Bir düğümün tüm alt düğümlerini dolaşır ve her birinin toJson() çıktısını
|
||||
// virgülle ayrılmış şekilde birleştirir.
|
||||
//
|
||||
// PARAMETRELER:
|
||||
// node — çocukları yazdırılacak düğüm
|
||||
// depth — JSON girinti seviyesi
|
||||
//
|
||||
// DÖNÜŞ: JSON array içeriği (köşeli parantezler HARİÇ)
|
||||
//
|
||||
// KULLANIM:
|
||||
// std::string json = childrenToJson(this, depth + 1);
|
||||
//
|
||||
// KARMAŞIKLIK: O(n) — n = çocuk sayısı
|
||||
//
|
||||
inline std::string childrenToJson(ASTNode* node, int depth) {
|
||||
std::ostringstream ss;
|
||||
std::string in = jsonIndent(depth);
|
||||
auto& ch = node->getChildren();
|
||||
for (size_t i = 0; i < ch.size(); i++) {
|
||||
ss << ch[i]->toJson(depth);
|
||||
if (i + 1 < ch.size()) ss << ",";
|
||||
if (i + 1 < ch.size()) ss << ","; // son elemandan sonra virgül yok
|
||||
ss << "\n";
|
||||
}
|
||||
return ss.str();
|
||||
|
|
|
|||
|
|
@ -1,307 +0,0 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — AST Deyim Düğümleri
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/ast_stmt.hpp
|
||||
// İÇERİK: Block, If, While, For, DoWhile,
|
||||
// Return, Break, Continue, ExpressionStatement
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_AST_STMT
|
||||
#define SAQUT_AST_STMT
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "parser/ast_node.hpp"
|
||||
#include "parser/ast_json.hpp"
|
||||
class BlockNode : public ASTNode {
|
||||
public:
|
||||
BlockNode() { kind = ASTKind::Block; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "Block\n";
|
||||
for (auto* c : getChildren()) c->log(indent + 2);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"Block\",\n"
|
||||
<< in << " \"children\": [\n"
|
||||
<< childrenToJson(this, depth + 3)
|
||||
<< in << " ]\n"
|
||||
<< in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class IfStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* condition = nullptr;
|
||||
ASTNode* thenBranch = nullptr;
|
||||
ASTNode* elseBranch = nullptr;
|
||||
|
||||
IfStatementNode() { kind = ASTKind::IfStatement; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "IfStatement\n";
|
||||
std::cout << padRight("", indent + 2) << "Condition:\n";
|
||||
if (condition) condition->log(indent + 4);
|
||||
std::cout << padRight("", indent + 2) << "Then:\n";
|
||||
if (thenBranch) thenBranch->log(indent + 4);
|
||||
if (elseBranch) {
|
||||
std::cout << padRight("", indent + 2) << "Else:\n";
|
||||
elseBranch->log(indent + 4);
|
||||
}
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"IfStatement\"";
|
||||
if (condition) {
|
||||
ss << ",\n" << in << " \"condition\":\n"
|
||||
<< condition->toJson(depth + 2);
|
||||
}
|
||||
if (thenBranch) {
|
||||
ss << ",\n" << in << " \"then\":\n"
|
||||
<< thenBranch->toJson(depth + 2);
|
||||
}
|
||||
if (elseBranch) {
|
||||
ss << ",\n" << in << " \"else\":\n"
|
||||
<< elseBranch->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class WhileStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* condition = nullptr;
|
||||
ASTNode* body = nullptr;
|
||||
|
||||
WhileStatementNode() { kind = ASTKind::WhileStatement; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "WhileStatement\n";
|
||||
std::cout << padRight("", indent + 2) << "Condition:\n";
|
||||
if (condition) condition->log(indent + 4);
|
||||
std::cout << padRight("", indent + 2) << "Body:\n";
|
||||
if (body) body->log(indent + 4);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"WhileStatement\"";
|
||||
if (condition) {
|
||||
ss << ",\n" << in << " \"condition\":\n"
|
||||
<< condition->toJson(depth + 2);
|
||||
}
|
||||
if (body) {
|
||||
ss << ",\n" << in << " \"body\":\n"
|
||||
<< body->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class ForStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* init = nullptr;
|
||||
ASTNode* condition = nullptr;
|
||||
ASTNode* update = nullptr;
|
||||
ASTNode* body = nullptr;
|
||||
|
||||
ForStatementNode() { kind = ASTKind::ForStatement; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "ForStatement\n";
|
||||
if (init) {
|
||||
std::cout << padRight("", indent + 2) << "Init:\n";
|
||||
init->log(indent + 4);
|
||||
}
|
||||
if (condition) {
|
||||
std::cout << padRight("", indent + 2) << "Condition:\n";
|
||||
condition->log(indent + 4);
|
||||
}
|
||||
if (update) {
|
||||
std::cout << padRight("", indent + 2) << "Update:\n";
|
||||
update->log(indent + 4);
|
||||
}
|
||||
std::cout << padRight("", indent + 2) << "Body:\n";
|
||||
if (body) body->log(indent + 4);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"ForStatement\"";
|
||||
if (init) {
|
||||
ss << ",\n" << in << " \"init\":\n"
|
||||
<< init->toJson(depth + 2);
|
||||
}
|
||||
if (condition) {
|
||||
ss << ",\n" << in << " \"condition\":\n"
|
||||
<< condition->toJson(depth + 2);
|
||||
}
|
||||
if (update) {
|
||||
ss << ",\n" << in << " \"update\":\n"
|
||||
<< update->toJson(depth + 2);
|
||||
}
|
||||
if (body) {
|
||||
ss << ",\n" << in << " \"body\":\n"
|
||||
<< body->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class DoWhileStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* condition = nullptr;
|
||||
ASTNode* body = nullptr;
|
||||
|
||||
DoWhileStatementNode() { kind = ASTKind::DoWhileStatement; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "DoWhileStatement\n";
|
||||
std::cout << padRight("", indent + 2) << "Body:\n";
|
||||
if (body) body->log(indent + 4);
|
||||
std::cout << padRight("", indent + 2) << "Condition:\n";
|
||||
if (condition) condition->log(indent + 4);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"DoWhileStatement\"";
|
||||
if (body) {
|
||||
ss << ",\n" << in << " \"body\":\n"
|
||||
<< body->toJson(depth + 2);
|
||||
}
|
||||
if (condition) {
|
||||
ss << ",\n" << in << " \"condition\":\n"
|
||||
<< condition->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// ReturnStatementNode — return [ifade]
|
||||
// ============================================================================
|
||||
|
||||
class ReturnStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* value = nullptr;
|
||||
|
||||
ReturnStatementNode() { kind = ASTKind::ReturnStatement; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "ReturnStatement";
|
||||
if (value) {
|
||||
std::cout << "\n";
|
||||
value->log(indent + 2);
|
||||
} else {
|
||||
std::cout << " (void)\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"ReturnStatement\"";
|
||||
if (value) {
|
||||
ss << ",\n" << in << " \"value\":\n"
|
||||
<< value->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// BreakStatementNode — break
|
||||
// ============================================================================
|
||||
|
||||
class BreakStatementNode : public ASTNode {
|
||||
public:
|
||||
BreakStatementNode() { kind = ASTKind::BreakStatement; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "BreakStatement\n";
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
return in + "{\n" + in + " \"kind\": \"BreakStatement\"\n" + in + "}";
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// ContinueStatementNode — continue
|
||||
// ============================================================================
|
||||
|
||||
class ContinueStatementNode : public ASTNode {
|
||||
public:
|
||||
ContinueStatementNode() { kind = ASTKind::ContinueStatement; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "ContinueStatement\n";
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
return in + "{\n" + in + " \"kind\": \"ContinueStatement\"\n" + in + "}";
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// ExpressionStatementNode — İfadeyi Statement Olarak Sarma
|
||||
// ============================================================================
|
||||
|
||||
class ExpressionStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* expression = nullptr;
|
||||
|
||||
ExpressionStatementNode() { kind = ASTKind::ExpressionStatement; }
|
||||
|
||||
void log(int indent = 0) override {
|
||||
std::cout << padRight("", indent) << "ExpressionStatement\n";
|
||||
if (expression) expression->log(indent + 2);
|
||||
}
|
||||
|
||||
std::string toJson(int depth = 0) override {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"ExpressionStatement\",\n"
|
||||
<< in << " \"location\": " << loc.toJson() << "";
|
||||
if (expression) {
|
||||
ss << ",\n" << in << " \"expression\":\n"
|
||||
<< expression->toJson(depth + 2);
|
||||
}
|
||||
ss << "\n" << in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// CallExpressionNode — Fonksiyon Çağrısı f(a, b, ...)
|
||||
// ============================================================================
|
||||
|
||||
#endif // SAQUT_AST_STMT
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#include "parser/nodes/binary_expr.hpp"
|
||||
#include "parser/ast_json.hpp"
|
||||
|
||||
BinaryExpressionNode::BinaryExpressionNode() {
|
||||
kind = ASTKind::BinaryExpression;
|
||||
}
|
||||
|
||||
void BinaryExpressionNode::log(int indent) {
|
||||
std::string in = jsonIndent(indent);
|
||||
std::cout << in << "BinaryExpression (" << (OPERATOR_MAP_REV.count(Operator) ? OPERATOR_MAP_REV.at(Operator) : "?") << ")\n";
|
||||
if (Left) Left->log(indent + 1);
|
||||
if (Right) Right->log(indent + 1);
|
||||
}
|
||||
|
||||
std::string BinaryExpressionNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "BinaryExpression");
|
||||
obj.add("operator", std::string(OPERATOR_MAP_REV.count(Operator) ? OPERATOR_MAP_REV.at(Operator) : "?"));
|
||||
if (Left) obj.addRaw("left", Left->toJson(depth + 1));
|
||||
if (Right) obj.addRaw("right", Right->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef SAQUT_AST_BINARY_EXPR
|
||||
#define SAQUT_AST_BINARY_EXPR
|
||||
|
||||
#include "parser/ast_node.hpp"
|
||||
|
||||
class BinaryExpressionNode : public ASTNode {
|
||||
public:
|
||||
TokenType Operator;
|
||||
ASTNode* Left = nullptr;
|
||||
ASTNode* Right = nullptr;
|
||||
|
||||
BinaryExpressionNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#include "parser/nodes/declarations.hpp"
|
||||
#include "parser/ast_json.hpp"
|
||||
|
||||
// FunctionDeclNode
|
||||
FunctionDeclNode::FunctionDeclNode() { kind = ASTKind::FunctionDecl; }
|
||||
void FunctionDeclNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "FunctionDecl (" << name << " : " << returnType << ")\n";
|
||||
for (auto* child : children) child->log(indent + 1);
|
||||
}
|
||||
std::string FunctionDeclNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "FunctionDecl");
|
||||
obj.add("name", name);
|
||||
obj.add("returnType", returnType);
|
||||
obj.addArray("children", [&]() {
|
||||
for (auto* child : children) obj.addItem(child->toJson(depth + 2));
|
||||
});
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// VariableDeclNode
|
||||
VariableDeclNode::VariableDeclNode() { kind = ASTKind::VariableDecl; }
|
||||
void VariableDeclNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "VariableDecl (" << name << " : " << varType << ")\n";
|
||||
if (initExpr) initExpr->log(indent + 1);
|
||||
}
|
||||
std::string VariableDeclNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "VariableDecl");
|
||||
obj.add("name", name);
|
||||
obj.add("varType", varType);
|
||||
if (initExpr) obj.addRaw("init", initExpr->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// StructDeclNode
|
||||
StructDeclNode::StructDeclNode() { kind = ASTKind::StructDecl; }
|
||||
void StructDeclNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "StructDecl (" << name << ")\n";
|
||||
for (auto* child : children) child->log(indent + 1);
|
||||
}
|
||||
std::string StructDeclNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "StructDecl");
|
||||
obj.add("name", name);
|
||||
obj.addArray("children", [&]() {
|
||||
for (auto* child : children) obj.addItem(child->toJson(depth + 2));
|
||||
});
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef SAQUT_AST_DECL
|
||||
#define SAQUT_AST_DECL
|
||||
|
||||
#include "parser/ast_node.hpp"
|
||||
|
||||
class FunctionDeclNode : public ASTNode {
|
||||
public:
|
||||
std::string name;
|
||||
std::string returnType;
|
||||
FunctionDeclNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class VariableDeclNode : public ASTNode {
|
||||
public:
|
||||
std::string varType;
|
||||
std::string name;
|
||||
ASTNode* initExpr = nullptr;
|
||||
VariableDeclNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class StructDeclNode : public ASTNode {
|
||||
public:
|
||||
std::string name;
|
||||
StructDeclNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#include "parser/nodes/expressions.hpp"
|
||||
#include "parser/ast_json.hpp"
|
||||
|
||||
// PostfixNode
|
||||
PostfixNode::PostfixNode() { kind = ASTKind::Postfix; }
|
||||
void PostfixNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "Postfix (" << (OPERATOR_MAP_REV.count(Operator) ? OPERATOR_MAP_REV.at(Operator) : "?") << ")\n";
|
||||
if (operand) operand->log(indent + 1);
|
||||
}
|
||||
std::string PostfixNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "Postfix");
|
||||
obj.add("operator", std::string(OPERATOR_MAP_REV.count(Operator) ? OPERATOR_MAP_REV.at(Operator) : "?"));
|
||||
if (operand) obj.addRaw("operand", operand->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// CallExpressionNode
|
||||
CallExpressionNode::CallExpressionNode() { kind = ASTKind::Call; }
|
||||
void CallExpressionNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "Call\n";
|
||||
if (callee) callee->log(indent + 1);
|
||||
for (auto* arg : arguments) arg->log(indent + 1);
|
||||
}
|
||||
std::string CallExpressionNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "Call");
|
||||
if (callee) obj.addRaw("callee", callee->toJson(depth + 1));
|
||||
obj.addArray("arguments", [&]() {
|
||||
for (auto* arg : arguments) obj.addItem(arg->toJson(depth + 2));
|
||||
});
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// MemberAccessNode
|
||||
MemberAccessNode::MemberAccessNode() { kind = ASTKind::MemberAccess; }
|
||||
void MemberAccessNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "MemberAccess (" << (arrow ? "->" : ".") << member << ")\n";
|
||||
if (object) object->log(indent + 1);
|
||||
}
|
||||
std::string MemberAccessNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "MemberAccess");
|
||||
obj.add("member", member);
|
||||
obj.add("arrow", arrow);
|
||||
if (object) obj.addRaw("object", object->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// IndexExpressionNode
|
||||
IndexExpressionNode::IndexExpressionNode() { kind = ASTKind::IndexExpression; }
|
||||
void IndexExpressionNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "IndexExpression\n";
|
||||
if (object) object->log(indent + 1);
|
||||
if (index) index->log(indent + 1);
|
||||
}
|
||||
std::string IndexExpressionNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "IndexExpression");
|
||||
if (object) obj.addRaw("object", object->toJson(depth + 1));
|
||||
if (index) obj.addRaw("index", index->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef SAQUT_AST_EXPR_EXT
|
||||
#define SAQUT_AST_EXPR_EXT
|
||||
|
||||
#include "parser/ast_node.hpp"
|
||||
|
||||
class PostfixNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* operand = nullptr;
|
||||
TokenType Operator;
|
||||
PostfixNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class CallExpressionNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* callee = nullptr;
|
||||
std::vector<ASTNode*> arguments;
|
||||
CallExpressionNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class MemberAccessNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* object = nullptr;
|
||||
std::string member;
|
||||
bool arrow = false;
|
||||
MemberAccessNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class IndexExpressionNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* object = nullptr;
|
||||
ASTNode* index = nullptr;
|
||||
IndexExpressionNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#include "parser/nodes/identifier.hpp"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "parser/ast_json.hpp"
|
||||
|
||||
IdentifierNode::IdentifierNode() { kind = ASTKind::Identifier; }
|
||||
|
||||
void IdentifierNode::log(int indent) {
|
||||
std::cout << padRight("", indent)
|
||||
<< "Identifier {" << (parserToken.token ? parserToken.token->token : "?") << "}\n";
|
||||
}
|
||||
|
||||
std::string IdentifierNode::toJson(int depth) {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::string name = parserToken.token ? parserToken.token->token : "?";
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"Identifier\",\n"
|
||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
||||
<< in << " \"location\": " << loc.toJson() << "\n"
|
||||
<< in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef SAQUT_AST_IDENTIFIER
|
||||
#define SAQUT_AST_IDENTIFIER
|
||||
|
||||
#include "parser/ast_node.hpp"
|
||||
|
||||
class IdentifierNode : public ASTNode {
|
||||
public:
|
||||
Token* lexerToken = nullptr;
|
||||
ParserToken parserToken;
|
||||
|
||||
IdentifierNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#include "parser/nodes/literal.hpp"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "parser/ast_json.hpp"
|
||||
|
||||
LiteralNode::LiteralNode() { kind = ASTKind::Literal; }
|
||||
|
||||
void LiteralNode::log(int indent) {
|
||||
std::cout << padRight("", indent)
|
||||
<< "Literal {" << (parserToken.token ? parserToken.token->token : "?") << "} "
|
||||
<< literalTypeToString(literalType);
|
||||
if (literalType == LiteralType::INTEGER && literalBase != 10)
|
||||
std::cout << " (base " << literalBase << ")";
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
std::string LiteralNode::toJson(int depth) {
|
||||
std::string in = jsonIndent(depth);
|
||||
std::string val = parserToken.token ? parserToken.token->token : "?";
|
||||
std::ostringstream ss;
|
||||
ss << in << "{\n"
|
||||
<< in << " \"kind\": \"Literal\",\n"
|
||||
<< in << " \"literalType\": \"" << literalTypeToString(literalType) << "\",\n"
|
||||
<< in << " \"value\": \"" << jsonEscape(val) << "\"";
|
||||
if (literalType == LiteralType::INTEGER && literalBase != 10) {
|
||||
ss << ",\n" << in << " \"base\": " << literalBase;
|
||||
}
|
||||
if (literalType == LiteralType::FLOAT) {
|
||||
ss << ",\n" << in << " \"isFloat\": true";
|
||||
}
|
||||
ss << ",\n" << in << " \"location\": " << loc.toJson() << "\n"
|
||||
<< in << "}";
|
||||
return ss.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef SAQUT_AST_LITERAL
|
||||
#define SAQUT_AST_LITERAL
|
||||
|
||||
#include "parser/ast_node.hpp"
|
||||
|
||||
class LiteralNode : public ASTNode {
|
||||
public:
|
||||
Token* lexerToken = nullptr;
|
||||
ParserToken parserToken;
|
||||
|
||||
LiteralType literalType = LiteralType::INTEGER;
|
||||
int literalBase = 10;
|
||||
bool isFloatValue = false;
|
||||
|
||||
LiteralNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#include "parser/nodes/program.hpp"
|
||||
#include "parser/ast_json.hpp"
|
||||
|
||||
ProgramNode::ProgramNode() {
|
||||
kind = ASTKind::Program;
|
||||
}
|
||||
|
||||
void ProgramNode::log(int indent) {
|
||||
std::string in = jsonIndent(indent);
|
||||
std::cout << in << "Program\n";
|
||||
for (auto* child : children) {
|
||||
child->log(indent + 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ProgramNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "Program");
|
||||
obj.addArray("children", [&]() {
|
||||
for (auto* child : children) {
|
||||
obj.addItem(child->toJson(depth + 2));
|
||||
}
|
||||
});
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef SAQUT_AST_PROGRAM
|
||||
#define SAQUT_AST_PROGRAM
|
||||
|
||||
#include "parser/ast_node.hpp"
|
||||
|
||||
class ProgramNode : public ASTNode {
|
||||
public:
|
||||
ProgramNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
#include "parser/nodes/statements.hpp"
|
||||
#include "parser/ast_json.hpp"
|
||||
|
||||
// BlockNode
|
||||
BlockNode::BlockNode() { kind = ASTKind::Block; }
|
||||
void BlockNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "Block\n";
|
||||
for (auto* child : children) child->log(indent + 1);
|
||||
}
|
||||
std::string BlockNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "Block");
|
||||
obj.addArray("children", [&]() {
|
||||
for (auto* child : children) obj.addItem(child->toJson(depth + 2));
|
||||
});
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// IfStatementNode
|
||||
IfStatementNode::IfStatementNode() { kind = ASTKind::IfStatement; }
|
||||
void IfStatementNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "IfStatement\n";
|
||||
if (condition) condition->log(indent + 1);
|
||||
if (thenBranch) thenBranch->log(indent + 1);
|
||||
if (elseBranch) elseBranch->log(indent + 1);
|
||||
}
|
||||
std::string IfStatementNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "IfStatement");
|
||||
if (condition) obj.addRaw("condition", condition->toJson(depth + 1));
|
||||
if (thenBranch) obj.addRaw("then", thenBranch->toJson(depth + 1));
|
||||
if (elseBranch) obj.addRaw("else", elseBranch->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// WhileStatementNode
|
||||
WhileStatementNode::WhileStatementNode() { kind = ASTKind::WhileStatement; }
|
||||
void WhileStatementNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "WhileStatement\n";
|
||||
if (condition) condition->log(indent + 1);
|
||||
if (body) body->log(indent + 1);
|
||||
}
|
||||
std::string WhileStatementNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "WhileStatement");
|
||||
if (condition) obj.addRaw("condition", condition->toJson(depth + 1));
|
||||
if (body) obj.addRaw("body", body->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// ForStatementNode
|
||||
ForStatementNode::ForStatementNode() { kind = ASTKind::ForStatement; }
|
||||
void ForStatementNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "ForStatement\n";
|
||||
if (init) init->log(indent + 1);
|
||||
if (condition) condition->log(indent + 1);
|
||||
if (update) update->log(indent + 1);
|
||||
if (body) body->log(indent + 1);
|
||||
}
|
||||
std::string ForStatementNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "ForStatement");
|
||||
if (init) obj.addRaw("init", init->toJson(depth + 1));
|
||||
if (condition) obj.addRaw("condition", condition->toJson(depth + 1));
|
||||
if (update) obj.addRaw("update", update->toJson(depth + 1));
|
||||
if (body) obj.addRaw("body", body->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// DoWhileStatementNode
|
||||
DoWhileStatementNode::DoWhileStatementNode() { kind = ASTKind::DoWhileStatement; }
|
||||
void DoWhileStatementNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "DoWhileStatement\n";
|
||||
if (body) body->log(indent + 1);
|
||||
if (condition) condition->log(indent + 1);
|
||||
}
|
||||
std::string DoWhileStatementNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "DoWhileStatement");
|
||||
if (condition) obj.addRaw("condition", condition->toJson(depth + 1));
|
||||
if (body) obj.addRaw("body", body->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// ReturnStatementNode
|
||||
ReturnStatementNode::ReturnStatementNode() { kind = ASTKind::ReturnStatement; }
|
||||
void ReturnStatementNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "ReturnStatement\n";
|
||||
if (value) value->log(indent + 1);
|
||||
}
|
||||
std::string ReturnStatementNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "ReturnStatement");
|
||||
if (value) obj.addRaw("value", value->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// BreakStatementNode
|
||||
BreakStatementNode::BreakStatementNode() { kind = ASTKind::BreakStatement; }
|
||||
void BreakStatementNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "BreakStatement\n";
|
||||
}
|
||||
std::string BreakStatementNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "BreakStatement");
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// ContinueStatementNode
|
||||
ContinueStatementNode::ContinueStatementNode() { kind = ASTKind::ContinueStatement; }
|
||||
void ContinueStatementNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "ContinueStatement\n";
|
||||
}
|
||||
std::string ContinueStatementNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "ContinueStatement");
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
||||
// ExpressionStatementNode
|
||||
ExpressionStatementNode::ExpressionStatementNode() { kind = ASTKind::ExpressionStatement; }
|
||||
void ExpressionStatementNode::log(int indent) {
|
||||
std::cout << jsonIndent(indent) << "ExpressionStatement\n";
|
||||
if (expression) expression->log(indent + 1);
|
||||
}
|
||||
std::string ExpressionStatementNode::toJson(int depth) {
|
||||
JsonObject obj(depth);
|
||||
obj.add("kind", "ExpressionStatement");
|
||||
if (expression) obj.addRaw("expression", expression->toJson(depth + 1));
|
||||
obj.addRaw("location", loc.toJson());
|
||||
return obj.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef SAQUT_AST_STMT
|
||||
#define SAQUT_AST_STMT
|
||||
|
||||
#include "parser/ast_node.hpp"
|
||||
|
||||
class BlockNode : public ASTNode {
|
||||
public:
|
||||
BlockNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class IfStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* condition = nullptr;
|
||||
ASTNode* thenBranch = nullptr;
|
||||
ASTNode* elseBranch = nullptr;
|
||||
IfStatementNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class WhileStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* condition = nullptr;
|
||||
ASTNode* body = nullptr;
|
||||
WhileStatementNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class ForStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* init = nullptr;
|
||||
ASTNode* condition = nullptr;
|
||||
ASTNode* update = nullptr;
|
||||
ASTNode* body = nullptr;
|
||||
ForStatementNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class DoWhileStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* condition = nullptr;
|
||||
ASTNode* body = nullptr;
|
||||
DoWhileStatementNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class ReturnStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* value = nullptr;
|
||||
ReturnStatementNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class BreakStatementNode : public ASTNode {
|
||||
public:
|
||||
BreakStatementNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class ContinueStatementNode : public ASTNode {
|
||||
public:
|
||||
ContinueStatementNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
class ExpressionStatementNode : public ASTNode {
|
||||
public:
|
||||
ASTNode* expression = nullptr;
|
||||
ExpressionStatementNode();
|
||||
void log(int indent = 0) override;
|
||||
std::string toJson(int depth = 0) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,599 @@
|
|||
#include "parser/parser.hpp"
|
||||
#include "parser/nodes/program.hpp"
|
||||
#include "parser/nodes/binary_expr.hpp"
|
||||
#include "parser/nodes/literal.hpp"
|
||||
#include "parser/nodes/identifier.hpp"
|
||||
#include "parser/nodes/expressions.hpp"
|
||||
#include "parser/nodes/statements.hpp"
|
||||
#include "parser/nodes/declarations.hpp"
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseToken: Ham Token'ı ParserToken'a dönüştür.
|
||||
// --------------------------------------------------------------------------
|
||||
ParserToken Parser::parseToken(Token* token) {
|
||||
ParserToken pt;
|
||||
pt.token = token;
|
||||
|
||||
std::string t = token->gettype();
|
||||
if (t == "string")
|
||||
pt.type = TokenType::STRING;
|
||||
else if (t == "number")
|
||||
pt.type = TokenType::NUMBER;
|
||||
else if (t == "operator")
|
||||
pt.type = OPERATOR_MAP.find(pt.token->token)->second;
|
||||
else if (t == "delimiter")
|
||||
pt.type = OPERATOR_MAP.find(pt.token->token)->second;
|
||||
else if (t == "keyword")
|
||||
pt.type = KEYWORD_MAP.find(pt.token->token)->second;
|
||||
else if (t == "identifier")
|
||||
pt.type = TokenType::IDENTIFIER;
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
ParserToken Parser::getToken(int offset) {
|
||||
if ((int)tokens.size() - 1 < current + offset) {
|
||||
ParserToken pt;
|
||||
pt.type = TokenType::SVR_VOID;
|
||||
return pt;
|
||||
}
|
||||
return parseToken(tokens[current + offset]);
|
||||
}
|
||||
|
||||
void Parser::nextToken() {
|
||||
if ((int)tokens.size() >= current + 1)
|
||||
current++;
|
||||
}
|
||||
|
||||
ParserToken Parser::lookahead(uint32_t forward) {
|
||||
return getToken(forward);
|
||||
}
|
||||
|
||||
ParserToken Parser::currentToken() {
|
||||
return getToken(0);
|
||||
}
|
||||
|
||||
ASTNode* Parser::parse(TokenList toks) {
|
||||
tokens = toks;
|
||||
current = 0;
|
||||
return parseProgram();
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseProgram() {
|
||||
ProgramNode* program = new ProgramNode();
|
||||
|
||||
while (currentToken().type != TokenType::SVR_VOID) {
|
||||
ASTNode* decl = parseDeclaration();
|
||||
if (decl)
|
||||
program->addChild(decl);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseDeclaration() {
|
||||
auto ct = currentToken();
|
||||
|
||||
if (ct.is({
|
||||
TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE,
|
||||
TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR,
|
||||
TokenType::KW_STRING_TYPE, TokenType::KW_AUTO
|
||||
})) {
|
||||
auto la1 = lookahead(1);
|
||||
auto la2 = lookahead(2);
|
||||
if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN)
|
||||
return parseFunctionDecl();
|
||||
return parseVariableDecl();
|
||||
}
|
||||
|
||||
if (ct.type == TokenType::KW_STRUCT)
|
||||
return parseStructDecl();
|
||||
|
||||
return parseStatement();
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseExpression() {
|
||||
return parseExpression(0);
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseExpression(uint16_t precedence) {
|
||||
if (currentToken().type == TokenType::SVR_VOID)
|
||||
return nullptr;
|
||||
|
||||
ASTNode* left = parseNullDenotation();
|
||||
if (!left) return nullptr;
|
||||
|
||||
while (true) {
|
||||
auto next = currentToken();
|
||||
if (next.type == TokenType::RPAREN ||
|
||||
next.type == TokenType::SEMICOLON ||
|
||||
next.type == TokenType::RBRACE ||
|
||||
next.type == TokenType::COMMA)
|
||||
break;
|
||||
|
||||
if (precedence < next.getPowerOperator()) {
|
||||
left = parseLeftDenotation(left);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseNullDenotation() {
|
||||
auto ct = currentToken();
|
||||
|
||||
if (ct.type == TokenType::SVR_VOID) {
|
||||
std::cerr << "Parser hatası: beklenmeyen dosya sonu\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (ct.type == TokenType::LPAREN) {
|
||||
nextToken();
|
||||
ASTNode* expr = parseExpression(0);
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken();
|
||||
return expr;
|
||||
}
|
||||
|
||||
if (ct.is({
|
||||
TokenType::PLUS_PLUS, TokenType::MINUS_MINUS,
|
||||
TokenType::PLUS, TokenType::MINUS,
|
||||
TokenType::BANG, TokenType::TILDE
|
||||
})) {
|
||||
nextToken();
|
||||
ASTNode* right = parseExpression(ct.getPowerOperator());
|
||||
BinaryExpressionNode* bin = new BinaryExpressionNode();
|
||||
bin->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
bin->Right = right;
|
||||
bin->Left = nullptr;
|
||||
bin->Operator = ct.type;
|
||||
if (right) right->parent = bin;
|
||||
return bin;
|
||||
}
|
||||
|
||||
if (ct.type == TokenType::NUMBER) {
|
||||
nextToken();
|
||||
LiteralNode* lit = new LiteralNode();
|
||||
lit->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
lit->lexerToken = ct.token;
|
||||
lit->parserToken = ct;
|
||||
if (auto* nt = dynamic_cast<NumberToken*>(ct.token)) {
|
||||
lit->literalBase = nt->base;
|
||||
lit->isFloatValue = nt->isFloat;
|
||||
lit->literalType = nt->isFloat ? LiteralType::FLOAT : LiteralType::INTEGER;
|
||||
}
|
||||
return lit;
|
||||
}
|
||||
|
||||
if (ct.type == TokenType::STRING) {
|
||||
nextToken();
|
||||
LiteralNode* lit = new LiteralNode();
|
||||
lit->literalType = LiteralType::STRING;
|
||||
lit->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
lit->lexerToken = ct.token;
|
||||
lit->parserToken = ct;
|
||||
return lit;
|
||||
}
|
||||
|
||||
if (ct.is({TokenType::KW_TRUE, TokenType::KW_FALSE, TokenType::KW_NULL})) {
|
||||
nextToken();
|
||||
LiteralNode* lit = new LiteralNode();
|
||||
if (ct.is({TokenType::KW_TRUE, TokenType::KW_FALSE}))
|
||||
lit->literalType = LiteralType::BOOLEAN;
|
||||
else
|
||||
lit->literalType = LiteralType::BOŞ;
|
||||
lit->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
lit->lexerToken = ct.token;
|
||||
lit->parserToken = ct;
|
||||
return lit;
|
||||
}
|
||||
|
||||
if (ct.type == TokenType::IDENTIFIER) {
|
||||
nextToken();
|
||||
IdentifierNode* id = new IdentifierNode();
|
||||
id->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
id->lexerToken = ct.token;
|
||||
id->parserToken = ct;
|
||||
return id;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseLeftDenotation(ASTNode* left) {
|
||||
auto ct = currentToken();
|
||||
|
||||
if (ct.is({TokenType::PLUS_PLUS, TokenType::MINUS_MINUS})) {
|
||||
nextToken();
|
||||
PostfixNode* pf = new PostfixNode();
|
||||
pf->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
pf->operand = left;
|
||||
pf->Operator = ct.type;
|
||||
left->parent = pf;
|
||||
return pf;
|
||||
}
|
||||
|
||||
if (ct.type == TokenType::LPAREN) {
|
||||
nextToken();
|
||||
CallExpressionNode* call = new CallExpressionNode();
|
||||
call->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
call->callee = left;
|
||||
left->parent = call;
|
||||
|
||||
if (currentToken().type != TokenType::RPAREN) {
|
||||
call->arguments.push_back(parseExpression(0));
|
||||
while (currentToken().type == TokenType::COMMA) {
|
||||
nextToken();
|
||||
call->arguments.push_back(parseExpression(0));
|
||||
}
|
||||
}
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken();
|
||||
return call;
|
||||
}
|
||||
|
||||
if (ct.type == TokenType::LBRACKET) {
|
||||
nextToken();
|
||||
IndexExpressionNode* idx = new IndexExpressionNode();
|
||||
idx->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
idx->object = left;
|
||||
left->parent = idx;
|
||||
idx->index = parseExpression(0);
|
||||
if (currentToken().type == TokenType::RBRACKET)
|
||||
nextToken();
|
||||
return idx;
|
||||
}
|
||||
|
||||
if (ct.type == TokenType::DOT || ct.type == TokenType::ARROW) {
|
||||
bool arrow = (ct.type == TokenType::ARROW);
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type != TokenType::IDENTIFIER) {
|
||||
std::cerr << "Parser hatasi: uye ismi bekleniyor\n";
|
||||
return left;
|
||||
}
|
||||
|
||||
MemberAccessNode* ma = new MemberAccessNode();
|
||||
ma->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
ma->object = left;
|
||||
ma->member = currentToken().token->token;
|
||||
ma->arrow = arrow;
|
||||
left->parent = ma;
|
||||
nextToken();
|
||||
return ma;
|
||||
}
|
||||
|
||||
uint16_t prec = ct.getPowerOperator();
|
||||
nextToken();
|
||||
|
||||
ASTNode* right = parseExpression(prec);
|
||||
|
||||
BinaryExpressionNode* bin = new BinaryExpressionNode();
|
||||
bin->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
bin->Left = left;
|
||||
bin->Right = right;
|
||||
bin->Operator = ct.type;
|
||||
if (left) left->parent = bin;
|
||||
if (right) right->parent = bin;
|
||||
return bin;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseFunctionDecl() {
|
||||
FunctionDeclNode* fn = new FunctionDeclNode();
|
||||
fn->loc = currentToken().token->loc;
|
||||
fn->returnType = currentToken().token->token;
|
||||
nextToken();
|
||||
|
||||
fn->name = currentToken().token->token;
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type == TokenType::LPAREN) {
|
||||
nextToken();
|
||||
while (currentToken().type != TokenType::RPAREN &&
|
||||
currentToken().type != TokenType::SVR_VOID)
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken();
|
||||
}
|
||||
|
||||
if (currentToken().type == TokenType::LBRACE) {
|
||||
ASTNode* body = parseBlock();
|
||||
fn->addChild(body);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseStructDecl() {
|
||||
StructDeclNode* st = new StructDeclNode();
|
||||
st->loc = currentToken().token->loc;
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::IDENTIFIER) {
|
||||
st->name = currentToken().token->token;
|
||||
nextToken();
|
||||
}
|
||||
if (currentToken().type == TokenType::LBRACE) {
|
||||
nextToken();
|
||||
while (currentToken().type != TokenType::RBRACE && currentToken().type != TokenType::SVR_VOID) {
|
||||
ASTNode* field = parseDeclaration();
|
||||
if (field) st->addChild(field);
|
||||
else break;
|
||||
}
|
||||
if (currentToken().type == TokenType::RBRACE) nextToken();
|
||||
}
|
||||
if (currentToken().type == TokenType::SEMICOLON) nextToken();
|
||||
return st;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseVariableDecl() {
|
||||
VariableDeclNode* vd = new VariableDeclNode();
|
||||
vd->loc = currentToken().token->loc;
|
||||
vd->varType = currentToken().token->token;
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type != TokenType::IDENTIFIER) {
|
||||
std::cerr << "Parser hatası: değişken ismi bekleniyor\n";
|
||||
return vd;
|
||||
}
|
||||
|
||||
vd->name = currentToken().token->token;
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type == TokenType::LBRACKET) {
|
||||
nextToken();
|
||||
while (currentToken().type != TokenType::RBRACKET &&
|
||||
currentToken().type != TokenType::SEMICOLON &&
|
||||
currentToken().type != TokenType::SVR_VOID)
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::RBRACKET)
|
||||
nextToken();
|
||||
}
|
||||
|
||||
if (currentToken().type == TokenType::EQUAL) {
|
||||
nextToken();
|
||||
vd->initExpr = parseExpression();
|
||||
}
|
||||
|
||||
while (currentToken().type == TokenType::COMMA) {
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type != TokenType::IDENTIFIER) {
|
||||
std::cerr << "Parser hatası: virgülden sonra değişken ismi bekleniyor\n";
|
||||
break;
|
||||
}
|
||||
|
||||
VariableDeclNode* sibling = new VariableDeclNode();
|
||||
sibling->loc = currentToken().token->loc;
|
||||
sibling->varType = vd->varType;
|
||||
sibling->name = currentToken().token->token;
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type == TokenType::LBRACKET) {
|
||||
nextToken();
|
||||
while (currentToken().type != TokenType::RBRACKET &&
|
||||
currentToken().type != TokenType::SEMICOLON &&
|
||||
currentToken().type != TokenType::SVR_VOID)
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::RBRACKET)
|
||||
nextToken();
|
||||
}
|
||||
|
||||
if (currentToken().type == TokenType::EQUAL) {
|
||||
nextToken();
|
||||
sibling->initExpr = parseExpression();
|
||||
}
|
||||
|
||||
vd->addChild(sibling);
|
||||
}
|
||||
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
|
||||
return vd;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseStatement() {
|
||||
auto ct = currentToken();
|
||||
|
||||
if (ct.type == TokenType::LBRACE)
|
||||
return parseBlock();
|
||||
|
||||
if (ct.type == TokenType::KW_IF)
|
||||
return parseIfStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_WHILE)
|
||||
return parseWhileStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_FOR)
|
||||
return parseForStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_DO)
|
||||
return parseDoWhileStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_RETURN)
|
||||
return parseReturnStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_BREAK)
|
||||
return parseBreakStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_CONTINUE)
|
||||
return parseContinueStatement();
|
||||
|
||||
if (ct.is({
|
||||
TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE,
|
||||
TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR,
|
||||
TokenType::KW_STRING_TYPE
|
||||
})) {
|
||||
return parseVariableDecl();
|
||||
}
|
||||
|
||||
if (ct.type == TokenType::KW_STRUCT)
|
||||
return parseStructDecl();
|
||||
|
||||
return parseExpressionStatement();
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseBlock() {
|
||||
BlockNode* block = new BlockNode();
|
||||
block->loc = currentToken().token ? currentToken().token->loc : SourceLocation{};
|
||||
|
||||
if (currentToken().type == TokenType::LBRACE)
|
||||
nextToken();
|
||||
|
||||
while (currentToken().type != TokenType::RBRACE &&
|
||||
currentToken().type != TokenType::SVR_VOID) {
|
||||
ASTNode* stmt = parseStatement();
|
||||
if (stmt)
|
||||
block->addChild(stmt);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentToken().type == TokenType::RBRACE)
|
||||
nextToken();
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseIfStatement() {
|
||||
IfStatementNode* ifNode = new IfStatementNode();
|
||||
ifNode->loc = currentToken().token->loc;
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type == TokenType::LPAREN) {
|
||||
nextToken();
|
||||
ifNode->condition = parseExpression();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken();
|
||||
}
|
||||
|
||||
ifNode->thenBranch = parseStatement();
|
||||
|
||||
if (currentToken().type == TokenType::KW_ELSE) {
|
||||
nextToken();
|
||||
ifNode->elseBranch = parseStatement();
|
||||
}
|
||||
|
||||
return ifNode;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseWhileStatement() {
|
||||
WhileStatementNode* ws = new WhileStatementNode();
|
||||
ws->loc = currentToken().token->loc;
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type == TokenType::LPAREN) {
|
||||
nextToken();
|
||||
ws->condition = parseExpression();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken();
|
||||
}
|
||||
|
||||
ws->body = parseStatement();
|
||||
return ws;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseForStatement() {
|
||||
ForStatementNode* fs = new ForStatementNode();
|
||||
fs->loc = currentToken().token->loc;
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type == TokenType::LPAREN)
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type != TokenType::SEMICOLON)
|
||||
fs->init = parseStatement();
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type != TokenType::SEMICOLON)
|
||||
fs->condition = parseExpression();
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type != TokenType::RPAREN)
|
||||
fs->update = parseExpression();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken();
|
||||
|
||||
fs->body = parseStatement();
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseDoWhileStatement() {
|
||||
DoWhileStatementNode* dw = new DoWhileStatementNode();
|
||||
dw->loc = currentToken().token->loc;
|
||||
nextToken();
|
||||
|
||||
dw->body = parseStatement();
|
||||
|
||||
if (currentToken().type == TokenType::KW_WHILE) {
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::LPAREN) {
|
||||
nextToken();
|
||||
dw->condition = parseExpression();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken();
|
||||
}
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
}
|
||||
|
||||
return dw;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseReturnStatement() {
|
||||
ReturnStatementNode* rs = new ReturnStatementNode();
|
||||
rs->loc = currentToken().token->loc;
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type != TokenType::SEMICOLON &&
|
||||
currentToken().type != TokenType::RBRACE) {
|
||||
rs->value = parseExpression();
|
||||
}
|
||||
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseBreakStatement() {
|
||||
BreakStatementNode* bs = new BreakStatementNode();
|
||||
bs->loc = currentToken().token->loc;
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
return bs;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseContinueStatement() {
|
||||
ContinueStatementNode* cs = new ContinueStatementNode();
|
||||
cs->loc = currentToken().token->loc;
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
return cs;
|
||||
}
|
||||
|
||||
ASTNode* Parser::parseExpressionStatement() {
|
||||
ExpressionStatementNode* es = new ExpressionStatementNode();
|
||||
es->loc = currentToken().token ? currentToken().token->loc : SourceLocation{};
|
||||
es->expression = parseExpression();
|
||||
if (!es->expression) {
|
||||
while (currentToken().type != TokenType::SEMICOLON &&
|
||||
currentToken().type != TokenType::RBRACE &&
|
||||
currentToken().type != TokenType::SVR_VOID)
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
}
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
|
||||
return es;
|
||||
}
|
||||
|
|
@ -1,32 +1,6 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — Parser (Aggregator)
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/parser.hpp
|
||||
// KATMAN: Katman 3 — Tokenizer'ı tüketir, AST üretir
|
||||
//
|
||||
// Bu dosya bir AGGREGATOR'dür. Parser'ın tüm bileşenlerini tek bir include
|
||||
// ile kullanılabilir yapar.
|
||||
//
|
||||
// MİMARİ:
|
||||
// parser_base.hpp — Parser sınıf tanımı
|
||||
// parser_core.hpp — parse, parseProgram, parseDeclaration, parseExpression
|
||||
// parser_decl.hpp — parseFunctionDecl, parseStructDecl, parseVariableDecl
|
||||
// parser_stmt.hpp — parseStatement, parseBlock, parseIf/While/For/...
|
||||
//
|
||||
// İKİ AYRI PARSER STRATEJİSİ:
|
||||
// 1. Pratt Parser (ifadeler için): Operatör önceliğini merkezi tabloda yönetir
|
||||
// 2. Recursive Descent (statement/deklarasyon): Her yapı kendi parse fonksiyonuna sahip
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_PARSER
|
||||
#define SAQUT_PARSER
|
||||
|
||||
// Sıralama önemli: önce sınıf tanımı, sonra metot gövdeleri
|
||||
#include "parser/parser_base.hpp"
|
||||
#include "parser/parser_core.hpp"
|
||||
#include "parser/parser_decl.hpp"
|
||||
#include "parser/parser_stmt.hpp"
|
||||
|
||||
#endif // SAQUT_PARSER
|
||||
|
|
|
|||
|
|
@ -1,409 +0,0 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — Parser Çekirdek (Program + İfadeler)
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/parser_core.hpp
|
||||
// İÇERİK: Token navigasyonu, parse(), parseProgram(),
|
||||
// parseDeclaration(), parseExpression() [Pratt]
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_PARSER_CORE
|
||||
#define SAQUT_PARSER_CORE
|
||||
|
||||
#include <iostream>
|
||||
#include "parser/parser_base.hpp"
|
||||
// --------------------------------------------------------------------------
|
||||
// parseToken: Ham Token'ı ParserToken'a dönüştür.
|
||||
//
|
||||
// Tokenizer'ın string tabanlı tip sistemini ("number", "operator", ...)
|
||||
// Parser'ın anlamsal tip sistemine (NUMBER, PLUS, KW_IF, ...) çevirir.
|
||||
//
|
||||
// BUG FIX (commit 40579ca): pt.token = token (pointer ataması).
|
||||
// Eskiden pt.token = *token (değer kopyası) object slicing yapıyordu.
|
||||
// --------------------------------------------------------------------------
|
||||
inline ParserToken Parser::parseToken(Token* token) {
|
||||
ParserToken pt;
|
||||
pt.token = token; // Pointer — değer kopyası DEĞİL
|
||||
|
||||
std::string t = token->gettype();
|
||||
if (t == "string")
|
||||
pt.type = TokenType::STRING;
|
||||
else if (t == "number")
|
||||
pt.type = TokenType::NUMBER;
|
||||
else if (t == "operator")
|
||||
pt.type = OPERATOR_MAP.find(pt.token->token)->second;
|
||||
else if (t == "delimiter")
|
||||
pt.type = OPERATOR_MAP.find(pt.token->token)->second;
|
||||
else if (t == "keyword")
|
||||
pt.type = KEYWORD_MAP.find(pt.token->token)->second;
|
||||
else if (t == "identifier")
|
||||
pt.type = TokenType::IDENTIFIER;
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// getToken: Güvenli token erişimi. Sınır dışı = SVR_VOID.
|
||||
// --------------------------------------------------------------------------
|
||||
inline ParserToken Parser::getToken(int offset) {
|
||||
if ((int)tokens.size() - 1 < current + offset) {
|
||||
ParserToken pt;
|
||||
pt.type = TokenType::SVR_VOID;
|
||||
return pt;
|
||||
}
|
||||
return parseToken(tokens[current + offset]);
|
||||
}
|
||||
|
||||
inline void Parser::nextToken() {
|
||||
if ((int)tokens.size() >= current + 1)
|
||||
current++;
|
||||
}
|
||||
|
||||
inline ParserToken Parser::lookahead(uint32_t forward) {
|
||||
return getToken(forward);
|
||||
}
|
||||
|
||||
inline ParserToken Parser::currentToken() {
|
||||
return getToken(0);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Üst Seviye
|
||||
// ============================================================================
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parse: Parser'ın ana giriş noktası. Token listesini alır, AST döndürür.
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parse(TokenList toks) {
|
||||
tokens = toks;
|
||||
current = 0;
|
||||
return parseProgram();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseProgram: Tüm üst seviye deklarasyonları/statement'ları ayrıştırır.
|
||||
//
|
||||
// Program ::= Declaration*
|
||||
// EOF'a (SVR_VOID) kadar parseDeclaration() çağrılır.
|
||||
//
|
||||
// BUG FIX (commit 438bc0e): Eskiden parseExpression() doğrudan çağrılıyordu,
|
||||
// bu sadece tek bir ifadeyi ayrıştırabiliyordu. Şimdi tam program desteği var.
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseProgram() {
|
||||
ProgramNode* program = new ProgramNode();
|
||||
|
||||
while (currentToken().type != TokenType::SVR_VOID) {
|
||||
ASTNode* decl = parseDeclaration();
|
||||
if (decl)
|
||||
program->addChild(decl);
|
||||
else
|
||||
break; // Hata durumunda döngüden çık
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Deklarasyonlar
|
||||
// ============================================================================
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseDeclaration: Üst seviye deklarasyon ayrıştırıcı.
|
||||
//
|
||||
// Strateji:
|
||||
// 1. Mevcut token bir tip keyword'ü mü (int, void, float, ...)?
|
||||
// - Evet → lookahead(2) '(' ise → fonksiyon tanımı
|
||||
// - Evet → değilse → değişken tanımı
|
||||
// 2. Değilse → statement (REPL modunda ifade de olabilir)
|
||||
//
|
||||
// LOOKAHEAD KULLANIMI:
|
||||
// "int main()" ve "int x = 10" ayrımı için 2 ileriye bakarız:
|
||||
// - int main() → lookahead(1)=identifier, lookahead(2)='('
|
||||
// - int x = 10 → lookahead(1)=identifier, lookahead(2)='='
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseDeclaration() {
|
||||
auto ct = currentToken();
|
||||
|
||||
// Tip keyword'ü ile başlayan → fonksiyon veya değişken
|
||||
if (ct.is({
|
||||
TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE,
|
||||
TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR,
|
||||
TokenType::KW_STRING_TYPE, TokenType::KW_AUTO
|
||||
})) {
|
||||
auto la1 = lookahead(1);
|
||||
auto la2 = lookahead(2);
|
||||
// int main( ... ) → fonksiyon
|
||||
if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN)
|
||||
return parseFunctionDecl();
|
||||
// int x ... → değişken
|
||||
return parseVariableDecl();
|
||||
}
|
||||
|
||||
// struct
|
||||
if (ct.type == TokenType::KW_STRUCT)
|
||||
return parseStructDecl();
|
||||
|
||||
// Tip keyword'ü değil → statement
|
||||
return parseStatement();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseFunctionDecl: Fonksiyon tanımı.
|
||||
|
||||
inline ASTNode* Parser::parseExpression() {
|
||||
return parseExpression(0);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseExpression(precedence): Pratt'ın ana döngüsü.
|
||||
//
|
||||
// Algoritma:
|
||||
// 1. NUD ile ilk operand'ı ayrıştır (prefix)
|
||||
// 2. Mevcut token bir operatör mü?
|
||||
// - Evet ve önceliği > precedence ise → LED ile infix ayrıştır
|
||||
// - Hayır veya öncelik <= precedence ise → dur, sol operand'ı döndür
|
||||
// 3. LED'in döndürdüğü düğüm yeni sol operand olur, 2. adıma dön
|
||||
//
|
||||
// DURMA KOŞULLARI:
|
||||
// - RPAREN, SEMICOLON, RBRACE, COMMA: İfade sonu sinyali
|
||||
// - Operatörün önceliği <= mevcut öncelik: Daha sıkı bağlanamaz
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseExpression(uint16_t precedence) {
|
||||
if (currentToken().type == TokenType::SVR_VOID)
|
||||
return nullptr;
|
||||
|
||||
// 1. Prefix (NUD)
|
||||
ASTNode* left = parseNullDenotation();
|
||||
if (!left) return nullptr;
|
||||
|
||||
// 2. Infix/Postfix döngüsü (LED)
|
||||
while (true) {
|
||||
auto next = currentToken();
|
||||
|
||||
// İfade sonu sinyalleri → dur
|
||||
if (next.type == TokenType::RPAREN ||
|
||||
next.type == TokenType::SEMICOLON ||
|
||||
next.type == TokenType::RBRACE ||
|
||||
next.type == TokenType::COMMA)
|
||||
break;
|
||||
|
||||
// Operatörün bağlanma gücü yetersiz → dur
|
||||
// (daha yüksek öncelikli bir bağlamdayız, bu operatör oraya ait değil)
|
||||
if (precedence < next.getPowerOperator()) {
|
||||
left = parseLeftDenotation(left);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseNullDenotation (NUD): Prefix ifadeleri.
|
||||
//
|
||||
// İşlenen prefix tipleri:
|
||||
// - Parantez: ( expression )
|
||||
// - Unary: +expr, -expr, !expr, ~expr, ++expr, --expr
|
||||
// - Literal: 42, "hello", true, false, null
|
||||
// - Identifier: x, myVar
|
||||
//
|
||||
// DÖNÜŞ: Ayrıştırılmış AST düğümü. Token TÜKETİLMİŞ olur (current ilerlemiş).
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseNullDenotation() {
|
||||
auto ct = currentToken();
|
||||
|
||||
if (ct.type == TokenType::SVR_VOID) {
|
||||
std::cerr << "Parser hatası: beklenmeyen dosya sonu\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// --- Parantezli ifade: ( expr ) ---
|
||||
// Önceliği sıfırlar — parantez içinde yeni bir ifade başlar.
|
||||
if (ct.type == TokenType::LPAREN) {
|
||||
nextToken(); // '(' tüket
|
||||
ASTNode* expr = parseExpression(0); // Öncelik sıfırla
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken(); // ')' tüket
|
||||
return expr;
|
||||
}
|
||||
|
||||
// --- Unary prefix operatörler: +, -, !, ~, ++, -- ---
|
||||
// PLUS ve MINUS burada UNARY olarak işlenir.
|
||||
// Binary olarak işlenmesi LED tarafından yapılır.
|
||||
//
|
||||
// ÖNEMLİ: PLUS ve MINUS için getPowerOperator() 13 döndürür (binary öncelik).
|
||||
// Ama burada unary olarak kullanılıyor. parseExpression(16) çağırmak daha
|
||||
// doğru olurdu ancak mevcut çalışma şekli de doğru sonuç veriyor.
|
||||
// TODO: Unary için ayrı öncelik seviyesi (örn: 16)
|
||||
if (ct.is({
|
||||
TokenType::PLUS_PLUS, TokenType::MINUS_MINUS,
|
||||
TokenType::PLUS, TokenType::MINUS,
|
||||
TokenType::BANG, TokenType::TILDE
|
||||
})) {
|
||||
nextToken(); // Operatörü tüket
|
||||
// Sağ operand'ı ayrıştır. Unary prefix sağdan sola bağlanır.
|
||||
ASTNode* right = parseExpression(ct.getPowerOperator());
|
||||
BinaryExpressionNode* bin = new BinaryExpressionNode();
|
||||
bin->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
bin->Right = right;
|
||||
bin->Left = nullptr; // Unary işaretçisi
|
||||
bin->Operator = ct.type;
|
||||
if (right) right->parent = bin;
|
||||
return bin;
|
||||
}
|
||||
|
||||
// --- Sayısal literal: 42, 0xFF, 3.14 ---
|
||||
if (ct.type == TokenType::NUMBER) {
|
||||
nextToken(); // Token'ı tüket
|
||||
LiteralNode* lit = new LiteralNode();
|
||||
lit->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
lit->lexerToken = ct.token;
|
||||
lit->parserToken = ct;
|
||||
// NumberToken'a cast edip base/isFloat bilgisini al
|
||||
if (auto* nt = dynamic_cast<NumberToken*>(ct.token)) {
|
||||
lit->literalBase = nt->base;
|
||||
lit->isFloatValue = nt->isFloat;
|
||||
lit->literalType = nt->isFloat ? LiteralType::FLOAT : LiteralType::INTEGER;
|
||||
}
|
||||
return lit;
|
||||
}
|
||||
|
||||
// --- String literal: "hello" ---
|
||||
if (ct.type == TokenType::STRING) {
|
||||
nextToken();
|
||||
LiteralNode* lit = new LiteralNode();
|
||||
lit->literalType = LiteralType::STRING;
|
||||
lit->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
lit->lexerToken = ct.token;
|
||||
lit->parserToken = ct;
|
||||
return lit;
|
||||
}
|
||||
|
||||
// --- Boolean/null literal: true, false, null ---
|
||||
if (ct.is({TokenType::KW_TRUE, TokenType::KW_FALSE, TokenType::KW_NULL})) {
|
||||
nextToken();
|
||||
LiteralNode* lit = new LiteralNode();
|
||||
// Token içeriğine göre boolean/null ayrımı
|
||||
if (ct.is({TokenType::KW_TRUE, TokenType::KW_FALSE}))
|
||||
lit->literalType = LiteralType::BOOLEAN;
|
||||
else
|
||||
lit->literalType = LiteralType::BOŞ;
|
||||
lit->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
lit->lexerToken = ct.token;
|
||||
lit->parserToken = ct;
|
||||
return lit;
|
||||
}
|
||||
|
||||
// --- Identifier: x, myVar ---
|
||||
if (ct.type == TokenType::IDENTIFIER) {
|
||||
nextToken();
|
||||
IdentifierNode* id = new IdentifierNode();
|
||||
id->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
id->lexerToken = ct.token;
|
||||
id->parserToken = ct;
|
||||
return id;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseLeftDenotation (LED): Infix ve Postfix ifadeler.
|
||||
//
|
||||
// Sol operand zaten ayrıştırılmış olarak gelir (left).
|
||||
// Mevcut token operatördür.
|
||||
//
|
||||
// İşlenen tipler:
|
||||
// - Postfix: expr++, expr--
|
||||
// - Binary infix: expr + expr, expr * expr, expr == expr, ...
|
||||
//
|
||||
// TASARIM NOTU: Postfix ve Binary aynı fonksiyonda işlenir çünkü ikisi de
|
||||
// "sol operand + operatör" pattern'ini takip eder. Postfix'te sağ operand
|
||||
// yoktur.
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseLeftDenotation(ASTNode* left) {
|
||||
auto ct = currentToken();
|
||||
|
||||
// --- Postfix: expr++, expr-- ---
|
||||
if (ct.is({TokenType::PLUS_PLUS, TokenType::MINUS_MINUS})) {
|
||||
nextToken();
|
||||
PostfixNode* pf = new PostfixNode();
|
||||
pf->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
pf->operand = left;
|
||||
pf->Operator = ct.type;
|
||||
left->parent = pf;
|
||||
return pf;
|
||||
}
|
||||
|
||||
// --- Fonksiyon cagrisi: expr(args) ---
|
||||
if (ct.type == TokenType::LPAREN) {
|
||||
nextToken();
|
||||
CallExpressionNode* call = new CallExpressionNode();
|
||||
call->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
call->callee = left;
|
||||
left->parent = call;
|
||||
|
||||
if (currentToken().type != TokenType::RPAREN) {
|
||||
call->arguments.push_back(parseExpression(0));
|
||||
while (currentToken().type == TokenType::COMMA) {
|
||||
nextToken();
|
||||
call->arguments.push_back(parseExpression(0));
|
||||
}
|
||||
}
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken();
|
||||
return call;
|
||||
}
|
||||
|
||||
// --- Dizi erisimi: expr[index] ---
|
||||
if (ct.type == TokenType::LBRACKET) {
|
||||
nextToken();
|
||||
IndexExpressionNode* idx = new IndexExpressionNode();
|
||||
idx->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
idx->object = left;
|
||||
left->parent = idx;
|
||||
idx->index = parseExpression(0);
|
||||
if (currentToken().type == TokenType::RBRACKET)
|
||||
nextToken();
|
||||
return idx;
|
||||
}
|
||||
|
||||
// --- Uye erisimi: expr.member / expr->member ---
|
||||
if (ct.type == TokenType::DOT || ct.type == TokenType::ARROW) {
|
||||
bool arrow = (ct.type == TokenType::ARROW);
|
||||
nextToken();
|
||||
|
||||
if (currentToken().type != TokenType::IDENTIFIER) {
|
||||
std::cerr << "Parser hatasi: uye ismi bekleniyor\n";
|
||||
return left;
|
||||
}
|
||||
|
||||
MemberAccessNode* ma = new MemberAccessNode();
|
||||
ma->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
ma->object = left;
|
||||
ma->member = currentToken().token->token;
|
||||
ma->arrow = arrow;
|
||||
left->parent = ma;
|
||||
nextToken();
|
||||
return ma;
|
||||
}
|
||||
|
||||
// --- Binary infix: expr OP expr ---
|
||||
uint16_t prec = ct.getPowerOperator();
|
||||
nextToken();
|
||||
|
||||
ASTNode* right = parseExpression(prec);
|
||||
|
||||
BinaryExpressionNode* bin = new BinaryExpressionNode();
|
||||
bin->loc = ct.token ? ct.token->loc : SourceLocation{};
|
||||
bin->Left = left;
|
||||
bin->Right = right;
|
||||
bin->Operator = ct.type;
|
||||
if (left) left->parent = bin;
|
||||
if (right) right->parent = bin;
|
||||
return bin;
|
||||
}
|
||||
|
||||
|
||||
#endif // SAQUT_PARSER_CORE
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — Parser Deklarasyonlar
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/parser_decl.hpp
|
||||
// İÇERİK: parseFunctionDecl(), parseStructDecl(), parseVariableDecl()
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_PARSER_DECL
|
||||
#define SAQUT_PARSER_DECL
|
||||
|
||||
#include <iostream>
|
||||
#include "parser/parser_base.hpp"
|
||||
inline ASTNode* Parser::parseFunctionDecl() {
|
||||
FunctionDeclNode* fn = new FunctionDeclNode();
|
||||
fn->loc = currentToken().token->loc;
|
||||
fn->returnType = currentToken().token->token; // "int", "void", ...
|
||||
nextToken(); // Dönüş tipini tüket
|
||||
|
||||
fn->name = currentToken().token->token; // "main", "calculate", ...
|
||||
nextToken(); // İsmi tüket
|
||||
|
||||
// Parametre listesi: ( ... )
|
||||
if (currentToken().type == TokenType::LPAREN) {
|
||||
nextToken(); // '(' tüket
|
||||
// TODO: Parametreleri ayrıştır
|
||||
// Şimdilik ')' gelene kadar atla
|
||||
while (currentToken().type != TokenType::RPAREN &&
|
||||
currentToken().type != TokenType::SVR_VOID)
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken(); // ')' tüket
|
||||
}
|
||||
|
||||
// Gövde: { ... }
|
||||
if (currentToken().type == TokenType::LBRACE) {
|
||||
ASTNode* body = parseBlock();
|
||||
fn->addChild(body);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
// --------------------------------------------------------------------------
|
||||
// parseStructDecl: struct tanimi.
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseStructDecl() {
|
||||
StructDeclNode* st = new StructDeclNode();
|
||||
st->loc = currentToken().token->loc;
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::IDENTIFIER) {
|
||||
st->name = currentToken().token->token;
|
||||
nextToken();
|
||||
}
|
||||
if (currentToken().type == TokenType::LBRACE) {
|
||||
nextToken();
|
||||
while (currentToken().type != TokenType::RBRACE && currentToken().type != TokenType::SVR_VOID) {
|
||||
ASTNode* field = parseDeclaration();
|
||||
if (field) st->addChild(field);
|
||||
else break;
|
||||
}
|
||||
if (currentToken().type == TokenType::RBRACE) nextToken();
|
||||
}
|
||||
if (currentToken().type == TokenType::SEMICOLON) nextToken();
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseVariableDecl: Değişken tanımı.
|
||||
//
|
||||
// Sözdizimi: Type Identifier [= Expression] {, Identifier [= Expression]} ;
|
||||
// Örnek: int x = 10;
|
||||
// float y; (initExpr = nullptr)
|
||||
// int first = 0, second = 1, next;
|
||||
//
|
||||
// Çoklu değişken:
|
||||
// İlk değişken ana düğüm olur. Virgülle ayrılmış ek değişkenler
|
||||
// ana düğümün children vektörüne eklenir. JSON çıktısında "declarators"
|
||||
// dizisi olarak görünür.
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseVariableDecl() {
|
||||
// --- Tip ve ilk değişken adı ---
|
||||
VariableDeclNode* vd = new VariableDeclNode();
|
||||
vd->loc = currentToken().token->loc;
|
||||
vd->varType = currentToken().token->token; // "int", "float", ...
|
||||
nextToken(); // Tipi tüket
|
||||
|
||||
if (currentToken().type != TokenType::IDENTIFIER) {
|
||||
std::cerr << "Parser hatası: değişken ismi bekleniyor\n";
|
||||
return vd;
|
||||
}
|
||||
|
||||
vd->name = currentToken().token->token;
|
||||
nextToken(); // İsmi tüket
|
||||
|
||||
// Opsiyonel array boyutu: [expr]
|
||||
if (currentToken().type == TokenType::LBRACKET) {
|
||||
nextToken(); // '['
|
||||
while (currentToken().type != TokenType::RBRACKET &&
|
||||
currentToken().type != TokenType::SEMICOLON &&
|
||||
currentToken().type != TokenType::SVR_VOID)
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::RBRACKET)
|
||||
nextToken(); // ']'
|
||||
}
|
||||
|
||||
// İlk değişkenin başlangıç değeri
|
||||
if (currentToken().type == TokenType::EQUAL) {
|
||||
nextToken(); // '=' tüket
|
||||
vd->initExpr = parseExpression();
|
||||
}
|
||||
|
||||
// --- Çoklu değişken: , identifier [= expr] ---
|
||||
while (currentToken().type == TokenType::COMMA) {
|
||||
nextToken(); // ',' tüket
|
||||
|
||||
if (currentToken().type != TokenType::IDENTIFIER) {
|
||||
std::cerr << "Parser hatası: virgülden sonra değişken ismi bekleniyor\n";
|
||||
break;
|
||||
}
|
||||
|
||||
VariableDeclNode* sibling = new VariableDeclNode();
|
||||
sibling->loc = currentToken().token->loc;
|
||||
sibling->varType = vd->varType; // Aynı tip
|
||||
sibling->name = currentToken().token->token;
|
||||
nextToken(); // İsmi tüket
|
||||
|
||||
// Opsiyonel array boyutu: [expr]
|
||||
if (currentToken().type == TokenType::LBRACKET) {
|
||||
nextToken(); // '['
|
||||
while (currentToken().type != TokenType::RBRACKET &&
|
||||
currentToken().type != TokenType::SEMICOLON &&
|
||||
currentToken().type != TokenType::SVR_VOID)
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::RBRACKET)
|
||||
nextToken(); // ']'
|
||||
}
|
||||
|
||||
// Başlangıç değeri
|
||||
if (currentToken().type == TokenType::EQUAL) {
|
||||
nextToken(); // '=' tüket
|
||||
sibling->initExpr = parseExpression();
|
||||
}
|
||||
|
||||
// Kardeş düğümü ana düğüme ekle
|
||||
vd->addChild(sibling);
|
||||
}
|
||||
|
||||
// Noktalı virgül (opsiyonel — parser hoşgörülü)
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
|
||||
return vd;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
#endif // SAQUT_PARSER_DECL
|
||||
|
|
@ -1,322 +0,0 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — Parser Deyimler
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/parser_stmt.hpp
|
||||
// İÇERİK: parseStatement(), parseBlock(), parseIf/While/For/DoWhile,
|
||||
// parseReturn/Break/Continue/ExpressionStatement
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_PARSER_STMT
|
||||
#define SAQUT_PARSER_STMT
|
||||
|
||||
#include <iostream>
|
||||
#include "parser/parser_base.hpp"
|
||||
inline ASTNode* Parser::parseStatement() {
|
||||
auto ct = currentToken();
|
||||
|
||||
if (ct.type == TokenType::LBRACE)
|
||||
return parseBlock();
|
||||
|
||||
if (ct.type == TokenType::KW_IF)
|
||||
return parseIfStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_WHILE)
|
||||
return parseWhileStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_FOR)
|
||||
return parseForStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_DO)
|
||||
return parseDoWhileStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_RETURN)
|
||||
return parseReturnStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_BREAK)
|
||||
return parseBreakStatement();
|
||||
|
||||
if (ct.type == TokenType::KW_CONTINUE)
|
||||
return parseContinueStatement();
|
||||
|
||||
// Değişken tanımı? (tip keyword'ü ile başlayan)
|
||||
if (ct.is({
|
||||
TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE,
|
||||
TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR,
|
||||
TokenType::KW_STRING_TYPE
|
||||
})) {
|
||||
return parseVariableDecl();
|
||||
}
|
||||
|
||||
// struct tanımı: struct Name { ... }
|
||||
if (ct.type == TokenType::KW_STRUCT)
|
||||
return parseStructDecl();
|
||||
|
||||
// Hiçbiri değilse → ifade statement'ı (atama, fonksiyon çağrısı, ...)
|
||||
return parseExpressionStatement();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseBlock: { statement* }
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseBlock() {
|
||||
BlockNode* block = new BlockNode();
|
||||
block->loc = currentToken().token ? currentToken().token->loc : SourceLocation{};
|
||||
|
||||
if (currentToken().type == TokenType::LBRACE)
|
||||
nextToken(); // '{' tüket
|
||||
|
||||
while (currentToken().type != TokenType::RBRACE &&
|
||||
currentToken().type != TokenType::SVR_VOID) {
|
||||
ASTNode* stmt = parseStatement();
|
||||
if (stmt)
|
||||
block->addChild(stmt);
|
||||
else
|
||||
break; // Hata durumunda döngüden çık
|
||||
}
|
||||
|
||||
if (currentToken().type == TokenType::RBRACE)
|
||||
nextToken(); // '}' tüket
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseIfStatement: if (expression) statement [else statement]
|
||||
//
|
||||
// Süslü parantez zorunlu DEĞİL — tek statement de olabilir.
|
||||
// if (x > 5) return x; ← geçerli
|
||||
// if (x > 5) { ... } ← geçerli
|
||||
//
|
||||
// TODO: Sallantılı else (dangling else) sorunu:
|
||||
// if (a) if (b) x; else y; ← else hangi if'e ait?
|
||||
// Mevcut implementasyon doğru: else en yakın if'e bağlanır.
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseIfStatement() {
|
||||
IfStatementNode* ifNode = new IfStatementNode();
|
||||
ifNode->loc = currentToken().token->loc;
|
||||
nextToken(); // 'if' tüket
|
||||
|
||||
// Koşul: ( expression )
|
||||
if (currentToken().type == TokenType::LPAREN) {
|
||||
nextToken(); // '(' tüket
|
||||
ifNode->condition = parseExpression();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken(); // ')' tüket
|
||||
}
|
||||
|
||||
// Then gövdesi
|
||||
ifNode->thenBranch = parseStatement();
|
||||
|
||||
// Opsiyonel else
|
||||
if (currentToken().type == TokenType::KW_ELSE) {
|
||||
nextToken(); // 'else' tüket
|
||||
ifNode->elseBranch = parseStatement();
|
||||
}
|
||||
|
||||
return ifNode;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseWhileStatement: while (expression) statement
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseWhileStatement() {
|
||||
WhileStatementNode* ws = new WhileStatementNode();
|
||||
ws->loc = currentToken().token->loc;
|
||||
nextToken(); // 'while' tüket
|
||||
|
||||
if (currentToken().type == TokenType::LPAREN) {
|
||||
nextToken(); // '(' tüket
|
||||
ws->condition = parseExpression();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken(); // ')' tüket
|
||||
}
|
||||
|
||||
ws->body = parseStatement();
|
||||
return ws;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseForStatement: for (init; condition; update) statement
|
||||
//
|
||||
// for'un 3 parçası da isteğe bağlıdır:
|
||||
// for (;;) { ... } ← sonsuz döngü (geçerli)
|
||||
//
|
||||
// init: VariableDeclNode veya ExpressionStatementNode
|
||||
// for (int i = 0; ...) → VariableDecl
|
||||
// for (i = 0; ...) → ExpressionStatement
|
||||
// condition: ifade (nullptr = yok)
|
||||
// update: ifade (nullptr = yok)
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseForStatement() {
|
||||
ForStatementNode* fs = new ForStatementNode();
|
||||
fs->loc = currentToken().token->loc;
|
||||
nextToken(); // 'for' tüket
|
||||
|
||||
if (currentToken().type == TokenType::LPAREN)
|
||||
nextToken(); // '(' tüket
|
||||
|
||||
// Init (opsiyonel)
|
||||
if (currentToken().type != TokenType::SEMICOLON)
|
||||
fs->init = parseStatement();
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken(); // ';' tüket
|
||||
|
||||
// Condition (opsiyonel)
|
||||
if (currentToken().type != TokenType::SEMICOLON)
|
||||
fs->condition = parseExpression();
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken(); // ';' tüket
|
||||
|
||||
// Update (opsiyonel)
|
||||
if (currentToken().type != TokenType::RPAREN)
|
||||
fs->update = parseExpression();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken(); // ')' tüket
|
||||
|
||||
// Body
|
||||
fs->body = parseStatement();
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseDoWhileStatement: do statement while (expression) ;
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseDoWhileStatement() {
|
||||
DoWhileStatementNode* dw = new DoWhileStatementNode();
|
||||
dw->loc = currentToken().token->loc;
|
||||
nextToken(); // 'do' tüket
|
||||
|
||||
// Gövde
|
||||
dw->body = parseStatement();
|
||||
|
||||
// while (expression) ;
|
||||
if (currentToken().type == TokenType::KW_WHILE) {
|
||||
nextToken(); // 'while' tüket
|
||||
if (currentToken().type == TokenType::LPAREN) {
|
||||
nextToken(); // '(' tüket
|
||||
dw->condition = parseExpression();
|
||||
if (currentToken().type == TokenType::RPAREN)
|
||||
nextToken(); // ')' tüket
|
||||
}
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken(); // ';' tüket
|
||||
}
|
||||
|
||||
return dw;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseReturnStatement: return [expression] ;
|
||||
//
|
||||
// return; ← value = nullptr (void fonksiyon)
|
||||
// return x + 1; ← value = BinaryExpression
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseReturnStatement() {
|
||||
ReturnStatementNode* rs = new ReturnStatementNode();
|
||||
rs->loc = currentToken().token->loc;
|
||||
nextToken(); // 'return' tüket
|
||||
|
||||
// Opsiyonel dönüş değeri
|
||||
// Eğer sıradaki token ; veya } ise → return;
|
||||
if (currentToken().type != TokenType::SEMICOLON &&
|
||||
currentToken().type != TokenType::RBRACE) {
|
||||
rs->value = parseExpression();
|
||||
}
|
||||
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken(); // ';' tüket
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseBreakStatement / parseContinueStatement
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseBreakStatement() {
|
||||
BreakStatementNode* bs = new BreakStatementNode();
|
||||
bs->loc = currentToken().token->loc;
|
||||
nextToken(); // 'break' tüket
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
return bs;
|
||||
}
|
||||
|
||||
inline ASTNode* Parser::parseContinueStatement() {
|
||||
ContinueStatementNode* cs = new ContinueStatementNode();
|
||||
cs->loc = currentToken().token->loc;
|
||||
nextToken(); // 'continue' tüket
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
return cs;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseExpressionStatement: expression ;
|
||||
//
|
||||
// Bir ifadeyi statement olarak kullanır. Örn: x = 5; foo();
|
||||
//
|
||||
// HATA KURTARMA:
|
||||
// Eğer parseExpression() başarısız olursa (nullptr), sonraki ; veya }
|
||||
// veya EOF'a kadar token'ları atlayarak senkronize olur. Bu, tek bir
|
||||
// hatalı ifadenin tüm parser'ı kilitlemesini önler.
|
||||
//
|
||||
// BUG FIX (commit 438bc0e): Eskiden hatalı ifade durumunda sonsuz
|
||||
// döngüye giriyordu (parseProgram her seferinde aynı ifadeyi okuyordu).
|
||||
// --------------------------------------------------------------------------
|
||||
inline ASTNode* Parser::parseExpressionStatement() {
|
||||
ExpressionStatementNode* es = new ExpressionStatementNode();
|
||||
es->loc = currentToken().token ? currentToken().token->loc : SourceLocation{};
|
||||
es->expression = parseExpression();
|
||||
if (!es->expression) {
|
||||
// Hata kurtarma: sonraki güvenli noktaya atla
|
||||
while (currentToken().type != TokenType::SEMICOLON &&
|
||||
currentToken().type != TokenType::RBRACE &&
|
||||
currentToken().type != TokenType::SVR_VOID)
|
||||
nextToken();
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
}
|
||||
if (currentToken().type == TokenType::SEMICOLON)
|
||||
nextToken();
|
||||
|
||||
return es;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// İfadeler — Pratt Parser (Top-Down Operator Precedence)
|
||||
// ============================================================================
|
||||
//
|
||||
// Pratt parser'ın temel fikri: Her operatörün bir "bağlanma gücü" (precedence)
|
||||
// vardır. Parser, bu güce göre operatörleri doğru sırada gruplar.
|
||||
//
|
||||
// NUD (Null Denotation): Prefix ifadeleri (sayılar, -, !, parantez)
|
||||
// LED (Left Denotation): Infix/Postfix ifadeler (+, *, ++)
|
||||
//
|
||||
// ÖRNEK: 1 + 2 * 3
|
||||
// 1. NUD: 1 → Literal(1)
|
||||
// 2. LED(+): prec=13, right'i parseExpression(13) ile ayrıştır
|
||||
// 2a. NUD: 2 → Literal(2)
|
||||
// 2b. LED(*): prec=14 > 13 → parseExpression(14)
|
||||
// 3a. NUD: 3 → Literal(3)
|
||||
// 3b. LED yok → dön
|
||||
// 2c. BinaryExpr(*, 2, 3) dön
|
||||
// 3. BinaryExpr(+, 1, BinaryExpr(*, 2, 3))
|
||||
// Sonuç: 1 + (2 * 3) ✓
|
||||
//
|
||||
// BUG FIX (commit 40579ca): Ana döngü lookahead(1) yerine currentToken()
|
||||
// kullanıyor. NUD artık token'ı tüketip ilerliyor, bu sayede currentToken()
|
||||
// her zaman bir sonraki operatörü gösterir.
|
||||
//
|
||||
// BUG FIX (commit 438bc0e): Atom'lar (sayı, string, identifier) NUD'da
|
||||
// nextToken() ile tüketiliyor. Eskiden tüketilmediği için sonsuz döngü
|
||||
// oluyordu.
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// parseExpression(): Öncelik 0'dan başla (en düşük bağlanma)
|
||||
|
||||
#endif // SAQUT_PARSER_STMT
|
||||
|
|
@ -1,65 +1,43 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — Parser Token Tipleri ve Operatör Öncelik Tablosu
|
||||
// saQut Compiler — Parser Token Tipleri, Operatör Öncelik Tablosu ve ParserToken
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/parser/token.hpp
|
||||
// KATMAN: Katman 3 — Tokenizer ile Parser arasında köprü
|
||||
// BAĞIMLI: Tokenizer (src/tokenizer/tokenizer.hpp)
|
||||
// KULLANAN: AST (src/parser/ast.hpp), Parser (src/parser/parser.hpp)
|
||||
// KATMAN: Katman 3 — Tokenizer ile Parser Arasında Köprü
|
||||
// AMAÇ: Tokenizer'ın ham token'larını anlamsal tiplere dönüştürmek,
|
||||
// operatör öncelik ve birleşme kurallarını merkezi olarak tanımlamak
|
||||
//
|
||||
// AMAÇ:
|
||||
// Tokenizer'ın ürettiği ham Token'ları (string tipli) Parser'ın anlayacağı
|
||||
// anlamsal tiplere (TokenType enum) dönüştürür. Ayrıca operatör önceliğini
|
||||
// (precedence) ve birleşme yönünü (associativity) merkezi olarak tanımlar.
|
||||
// BAĞIMLILIKLAR:
|
||||
// - tokenizer/tokenizer.hpp: Token sınıf hiyerarşisi (Token, NumberToken, vs.)
|
||||
// - KULLANAN: parser/ast.hpp, parser/parser.hpp
|
||||
//
|
||||
// Bu dosya, Pratt parser'ın "kalbi"dir — tüm operatör önceliği ve birleşme
|
||||
// kuralları burada tek bir yerde tanımlanır.
|
||||
// BU DOSYANIN İÇERDİKLERİ:
|
||||
// 1. TokenType enum (uint16_t): 100+ token tipi (keyword'ler, operatörler, delimiter'lar)
|
||||
// 2. KEYWORD_MAP: string → TokenType (keyword çözümleme)
|
||||
// 3. OPERATOR_MAP: string → TokenType (operatör çözümleme)
|
||||
// 4. OPERATOR_MAP_REV: TokenType → string (log çıktısı için ters harita)
|
||||
// 5. OPERATOR_MAP_STRREV: TokenType → string (enum ismi, debug için)
|
||||
// 6. TokenPrecedence(): Öncelik tablosu (18 seviye, Pratt parser'ın kalbi)
|
||||
// 7. RightAssociative(): Sağ birleşme kontrolü (atama, üs, ternary)
|
||||
// 8. ParserToken: Parser'ın kullandığı token yapısı (Token* + TokenType)
|
||||
//
|
||||
// ADR-002: Neden Merkezi Operatör Öncelik Tablosu?
|
||||
// Recursive descent parser'larda operatör önceliği, her seviye için ayrı
|
||||
// bir fonksiyon yazılarak (parseAddExpr, parseMulExpr, ...) kod tekrarına
|
||||
// neden olur. Yeni bir operatör eklemek için yeni fonksiyon + mevcut
|
||||
// fonksiyonları değiştirmek gerekir.
|
||||
// TASARIM KARARLARI (ADR-002):
|
||||
// Neden TokenType enum'ı burada tanımlı, Tokenizer'da değil?
|
||||
// -> Tokenizer sadece ham token'lar üretir. Anlamsal tipler Parser'ın işidir.
|
||||
// -> Tokenizer'ın Tokenizer'ın ham yapısını değiştirmeden yeni diller eklenebilir.
|
||||
//
|
||||
// Pratt parser'da tüm öncelik bilgisi TEK BİR TABLODA (TokenPrecedence)
|
||||
// toplanır. Yeni operatör eklemek = tabloya bir satır eklemek.
|
||||
// Neden uint16_t tabanlı enum?
|
||||
// -> 65K token tipi fazlasıyla yeterli. 2 byte = bellek tasarrufu.
|
||||
// -> Her AST düğümünde TokenType saklanabilir (opsiyonel).
|
||||
//
|
||||
// TASARIM KARARLARI:
|
||||
// 1. TokenType enum: uint16_t tabanlı. Neden? 65K'dan fazla token tipi
|
||||
// olmayacak, 2 byte yeterli. Bellek tasarrufu AST'de fark eder.
|
||||
// Neden dört ayrı map?
|
||||
// -> unordered_map tek yönlüdür. Her yön için ayrı map gerekir.
|
||||
// -> OPERATOR_MAP_REV: log çıktısında "+" göstermek için.
|
||||
// -> OPERATOR_MAP_STRREV: enum ismini string olarak (debug, AST dump).
|
||||
//
|
||||
// 2. Üç harita (KEYWORD_MAP, OPERATOR_MAP, OPERATOR_MAP_REV, OPERATOR_MAP_STRREV):
|
||||
// - KEYWORD_MAP: "if" → KW_IF, string'den TokenType'a
|
||||
// - OPERATOR_MAP: "+" → PLUS, operatör string'inden TokenType'a
|
||||
// - OPERATOR_MAP_REV: PLUS → "+", log çıktısı için ters harita
|
||||
// - OPERATOR_MAP_STRREV: PLUS → "PLUS", enum ismini string olarak verir
|
||||
// Neden dört harita? Çünkü std::unordered_map tek yönlüdür.
|
||||
// bidirectional_map kütüphanesi kullanılabilirdi ama bağımlılık istemedik.
|
||||
//
|
||||
// 3. TokenPrecedence(): 18 seviyeli öncelik sistemi.
|
||||
// C/C++/Java standartlarına uygun. Yüksek sayı = yüksek öncelik.
|
||||
// Seviye 18 (en yüksek): üye erişimi (., ->, [], (), ::)
|
||||
// Seviye 1 (en düşük): virgül (,)
|
||||
// Seviye 0: önceliksiz (değerler, EOF, vb.)
|
||||
//
|
||||
// 4. RightAssociative(): Hangi operatörler sağdan sola birleşir?
|
||||
// - Atama (=, +=, vb.)
|
||||
// - Üs alma (**, ^) — matematiksel sağ birleşme: a^b^c = a^(b^c)
|
||||
// - Ternary (?:)
|
||||
// Diğer tüm operatörler soldan sağa birleşir.
|
||||
//
|
||||
// 5. ParserToken yapısı:
|
||||
// Token* token: Tokenizer'ın ürettiği Token'a pointer. Değer kopyası
|
||||
// DEĞİL. Neden pointer? Çünkü Token polimorfik (NumberToken, StringToken,
|
||||
// vb.) ve değer kopyası object slicing'e neden olur.
|
||||
// BUG FIX (commit 40579ca): Eskiden Token token (değer) vardı.
|
||||
// TokenType type: Token'ın anlamsal tipi.
|
||||
// is() / getPowerOperator() / isRightAssociative(): kolaylık metotları.
|
||||
//
|
||||
// BİLİNEN SINIRLAMALAR (TODO):
|
||||
// TODO: Özel operatörler: ?., ??, |>, >>=, vb. (ileride eklenebilir)
|
||||
// TODO: Kullanıcı tanımlı operatör önceliği (DSL'ler için)
|
||||
// TODO: Token konum bilgisi (satır/sütun) ParserToken'a eklenmeli
|
||||
// Neden bu kadar çok keyword?
|
||||
// -> saQut hem C/C++ hem Java hem de kendi sözdizimini destekler.
|
||||
// -> Tüm keyword'ler tek enum'da toplanmıştır.
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
|
|
@ -107,185 +85,334 @@ typedef std::vector<Token*> TokenList;
|
|||
// NEDEN uint16_t? Bellek optimizasyonu. Her AST düğümü bir TokenType taşır.
|
||||
// Binlerce düğümde 2 byte vs 4 byte fark eder.
|
||||
//
|
||||
/* ================================================================
|
||||
* TokenType — Anlamsal Token Tipleri
|
||||
* ================================================================
|
||||
*
|
||||
* Tokenizer'ın ürettiği ham token'ları (string tipli) Parser'ın
|
||||
* anlayacağı anlamsal tiplere dönüştürür.
|
||||
*
|
||||
* uint16_t tabanlı — 65K token tipi yeterli.
|
||||
* Bellek: AST düğümlerinde taşınabilir (2 byte).
|
||||
*
|
||||
* KATEGORİLER (öncelik sırasına göre):
|
||||
* 1. Değerler: IDENTIFIER, NUMBER, STRING, SVR_VOID
|
||||
* 2. Keyword'ler: KW_IF ... KW_NOEXCEPT (C/C++/Java ortak)
|
||||
* 3. Operatörler: DOT(18) ... COMMA(1) (Pratt öncelik seviyesi)
|
||||
* 4. Delimiter'lar: LBRACE, RBRACE, SEMICOLON, vb.
|
||||
* 5. Özel: END_OF_FILE, UNKNOWN, COMMENT, PREPROCESSOR
|
||||
*
|
||||
* ================================================================ */
|
||||
enum class TokenType : uint16_t {
|
||||
// --- Değerler ve Tanımlayıcılar ---
|
||||
IDENTIFIER, // değişken/fonksiyon ismi
|
||||
NUMBER, // 42, 0xFF, 0b1010, 3.14
|
||||
STRING, // "merhaba"
|
||||
SVR_VOID, // Geçersiz/EOF sinyali (Parser içinde kullanılır)
|
||||
/* ====== Değerler ve Tanımlayıcılar ====== */
|
||||
IDENTIFIER, // Değişken/fonksiyon/sınıf ismi.
|
||||
// Tokenizer'da IdentifierToken olarak üretilir.
|
||||
// Örn: x, main, Point, calculateAverage
|
||||
NUMBER, // Sayısal sabit: 42, 0xFF, 0b1010, 3.14, 1e-5
|
||||
// Tokenizer'da NumberToken olarak üretilir.
|
||||
// .isFloat alanı ile tamsayı/ondalık ayrımı yapılır.
|
||||
STRING, // Metin sabiti: "merhaba", "selam"
|
||||
// Tokenizer'da StringToken olarak üretilir.
|
||||
// Kaçış dizileri (\n, \t, \") tokenizer'da çözülür.
|
||||
SVR_VOID, // Geçersiz/EOF sinyali.
|
||||
// Parser içinde kullanılır. Tokenizer ÜRETMEZ.
|
||||
// currentToken() geçersiz indeks gösterdiğinde döner.
|
||||
|
||||
// --- Kontrol Akışı Keyword'leri ---
|
||||
KW_IF, // if
|
||||
KW_ELSE, // else
|
||||
KW_FOR, // for
|
||||
KW_WHILE, // while
|
||||
KW_DO, // do
|
||||
KW_SWITCH, // switch
|
||||
KW_CASE, // case
|
||||
KW_DEFAULT, // default
|
||||
KW_BREAK, // break
|
||||
KW_CONTINUE, // continue
|
||||
KW_RETURN, // return
|
||||
/* ====== Kontrol Akışı Keyword'leri ====== */
|
||||
KW_IF, // if (koşullu dal)
|
||||
// Sözdizimi: if (koşul) gövde [else gövde]
|
||||
KW_ELSE, // else (if'in alternatif dalı)
|
||||
// Sözdizimi: if (...) ... else ...
|
||||
// Parser'da if'ten sonra else opsiyoneldir.
|
||||
KW_FOR, // for (tekrarlı döngü)
|
||||
// Sözdizimi: for (init; koşul; artım) gövde
|
||||
KW_WHILE, // while (koşullu döngü)
|
||||
// Sözdizimi: while (koşul) gövde
|
||||
KW_DO, // do (en az bir kez çalışan döngü)
|
||||
// Sözdizimi: do gövde while (koşul);
|
||||
KW_SWITCH, // switch (çoklu dal — henüz implemente edilmedi)
|
||||
KW_CASE, // case (switch dalı — henüz implemente edilmedi)
|
||||
KW_DEFAULT, // default (switch varsayılan — henüz implemente edilmedi)
|
||||
KW_BREAK, // break (döngü/switch'ten çık)
|
||||
// Sadece döngü veya switch içinde geçerlidir.
|
||||
KW_CONTINUE, // continue (döngünün bir sonraki iterasyonuna geç)
|
||||
// Sadece döngü içinde geçerlidir.
|
||||
KW_RETURN, // return (fonksiyondan dön)
|
||||
// İsteğe bağlı dönüş değeri: return expr;
|
||||
|
||||
// --- OOP Keyword'leri ---
|
||||
KW_CLASS, // class
|
||||
KW_STRUCT, // struct
|
||||
KW_INTERFACE, // interface
|
||||
KW_ENUM, // enum
|
||||
KW_EXTENDS, // extends
|
||||
KW_IMPLEMENTS, // implements
|
||||
KW_NEW, // new
|
||||
KW_PUBLIC, // public
|
||||
KW_PRIVATE, // private
|
||||
KW_PROTECTED, // protected
|
||||
KW_STATIC, // static
|
||||
KW_FINAL, // final
|
||||
KW_ABSTRACT, // abstract
|
||||
/* ====== OOP Keyword'leri ====== */
|
||||
KW_CLASS, // class (sınıf tanımı — Java/C++ tarzı)
|
||||
KW_STRUCT, // struct (yapı tanımı — C tarzı)
|
||||
// saQut'ta class ve struct ikisi de desteklenir.
|
||||
KW_INTERFACE, // interface (soyut tip — Java tarzı)
|
||||
KW_ENUM, // enum (sabit listesi — C/C++/Java tarzı)
|
||||
KW_EXTENDS, // extends (kalıtım — Java tarzı)
|
||||
KW_IMPLEMENTS, // implements (interface gerçekleme — Java tarzı)
|
||||
KW_NEW, // new (nesne oluşturma — Java/C++ tarzı)
|
||||
KW_PUBLIC, // public (erişim belirteci)
|
||||
KW_PRIVATE, // private (erişim belirteci)
|
||||
KW_PROTECTED, // protected (erişim belirteci — alt sınıflara açık)
|
||||
KW_STATIC, // static (sınıf üyesi / dosya içi bağlantı)
|
||||
KW_FINAL, // final (değiştirilemez — Java tarzı)
|
||||
KW_ABSTRACT, // abstract (soyut sınıf/metot — Java tarzı)
|
||||
|
||||
// --- Tip Keyword'leri ---
|
||||
KW_VOID, // void
|
||||
KW_BOOL, // bool
|
||||
KW_INT, // int
|
||||
KW_FLOAT_TYPE, // float (FLOAT math.h'de tanımlı olabilir, TYPE eki var)
|
||||
KW_DOUBLE, // double
|
||||
KW_CHAR, // char
|
||||
KW_STRING_TYPE, // string
|
||||
/* ====== Tip Keyword'leri ====== */
|
||||
KW_VOID, // void (değer döndürmeyen fonksiyon / tip yok)
|
||||
// C/C++/Java uyumluluğu için.
|
||||
KW_BOOL, // bool (mantıksal tip: true/false)
|
||||
// C++ bool ile aynı.
|
||||
KW_INT, // int (tamsayı tipi: 32-bit işaretli)
|
||||
// Varsayılan tamsayı tipi.
|
||||
KW_FLOAT_TYPE, // float (32-bit ondalıklı sayı)
|
||||
// FLOAT_MATH hatasından kaçınmak için _TYPE eki.
|
||||
// math.h'deki float tanımıyla çakışmaz.
|
||||
KW_DOUBLE, // double (64-bit ondalıklı sayı)
|
||||
KW_CHAR, // char (8-bit karakter)
|
||||
// Tek tırnak içindeki karakterler için: 'A'
|
||||
KW_STRING_TYPE, // string (metin tipi)
|
||||
// string.h'daki string işlevleriyle çakışmaz.
|
||||
|
||||
// --- Literal Keyword'ler ---
|
||||
KW_TRUE, // true
|
||||
KW_FALSE, // false
|
||||
KW_NULL, // null
|
||||
/* ====== Literal Keyword'ler ====== */
|
||||
KW_TRUE, // true (mantıksal doğru sabiti)
|
||||
// Boolean literal: if (true) { ... }
|
||||
KW_FALSE, // false (mantıksal yanlış sabiti)
|
||||
// Boolean literal: while (false) { ... }
|
||||
KW_NULL, // null (boş referans sabiti)
|
||||
// Pointer/referans tipleri için: Object obj = null;
|
||||
|
||||
// --- İstisna Yönetimi ---
|
||||
KW_TRY, // try
|
||||
KW_CATCH, // catch
|
||||
KW_FINALLY, // finally
|
||||
KW_THROW, // throw
|
||||
KW_THROWS, // throws
|
||||
KW_ASSERT, // assert
|
||||
/* ====== İstisna Yönetimi ====== */
|
||||
KW_TRY, // try (istisna deneme bloğu — Java/C++ tarzı)
|
||||
// Sözdizimi: try { ... } catch (Ex e) { ... }
|
||||
KW_CATCH, // catch (istisna yakalama bloğu)
|
||||
KW_FINALLY, // finally (her durumda çalışan blok — Java tarzı)
|
||||
KW_THROW, // throw (istisna fırlatma — C++/Java tarzı)
|
||||
// Sözdizimi: throw new Exception("hata");
|
||||
KW_THROWS, // throws (metot imzasında istisna bildirimi — Java)
|
||||
KW_ASSERT, // assert (debug assertions — C/Java tarzı)
|
||||
|
||||
// --- Modül/Paket ---
|
||||
KW_IMPORT, // import
|
||||
KW_PACKAGE, // package
|
||||
/* ====== Modül/Paket ====== */
|
||||
KW_IMPORT, // import (modül içe aktarma — Java/Python tarzı)
|
||||
// Sözdizimi: import java.util.List;
|
||||
KW_PACKAGE, // package (modül bildirimi — Java tarzı)
|
||||
// Sözdizimi: package com.saqut.compiler;
|
||||
|
||||
// --- C/C++ Ekleri ---
|
||||
KW_NATIVE, // native (JNI)
|
||||
KW_SYNCHRONIZED, // synchronized (Java)
|
||||
KW_VOLATILE, // volatile
|
||||
KW_TRANSIENT, // transient
|
||||
KW_CONST, // const
|
||||
KW_EXTERN, // extern
|
||||
KW_TYPEDEF, // typedef
|
||||
KW_SIZEOF, // sizeof
|
||||
KW_ALIGNOF, // alignof
|
||||
KW_DECLTYPE, // decltype
|
||||
KW_AUTO, // auto
|
||||
KW_CONSTEXPR, // constexpr
|
||||
KW_NOEXCEPT, // noexcept
|
||||
/* ====== C/C++ Ekleri ====== */
|
||||
KW_NATIVE, // native (yerel kod bildirimi — JNI)
|
||||
// Java native metotları için.
|
||||
KW_SYNCHRONIZED, // synchronized (iş parçacığı senkronizasyonu — Java)
|
||||
KW_VOLATILE, // volatile (derleyici optimizasyonunu engelle — C/C++/Java)
|
||||
KW_TRANSIENT, // transient (serileştirmeyi atla — Java)
|
||||
KW_CONST, // const (değişmez değer — C/C++ tarzı)
|
||||
// Örn: const int MAX = 100;
|
||||
KW_EXTERN, // extern (harici bağlantı — C/C++ tarzı)
|
||||
KW_TYPEDEF, // typedef (tip takma adı — C/C++ tarzı)
|
||||
KW_SIZEOF, // sizeof (tip/boyut sorgulama — C/C++ tarzı)
|
||||
// Sözdizimi: sizeof(int) veya sizeof x
|
||||
KW_ALIGNOF, // alignof (hizalama sorgulama — C++11)
|
||||
KW_DECLTYPE, // decltype (ifade tipi çıkarımı — C++11)
|
||||
KW_AUTO, // auto (otomatik tip çıkarımı — C++11)
|
||||
KW_CONSTEXPR, // constexpr (derleme zamanı sabiti — C++11)
|
||||
KW_NOEXCEPT, // noexcept (istisna fırlatmayan bildirimi — C++11)
|
||||
|
||||
// ================================================================
|
||||
// Operatörler — Öncelik sırasına göre gruplanmış
|
||||
// ================================================================
|
||||
/* ================================================================
|
||||
* Operatörler — Öncelik sırasına göre gruplanmış
|
||||
*
|
||||
* Her operatörün yanında Pratt parser öncelik seviyesi yazılıdır.
|
||||
* Yüksek sayı = daha sıkı bağlanma (önce işlenir).
|
||||
*
|
||||
* Seviye 18 (en yüksek): Üye erişimi ve çağrı
|
||||
* Seviye 17: Postfix ++ --
|
||||
* Seviye 16: Unary prefix + - ! ~
|
||||
* Seviye 15: Üs alma ** ^
|
||||
* Seviye 14: Çarpma/Bölme * / %
|
||||
* Seviye 13: Toplama/Çıkarma + -
|
||||
* Seviye 12: Bitsel kaydırma << >>
|
||||
* Seviye 11: İlişkisel < <= > >=
|
||||
* Seviye 10: Eşitlik == !=
|
||||
* Seviye 9: Bitsel VE &
|
||||
* Seviye 8: Bitsel XOR ^ (CARET üs olarak 15'te)
|
||||
* Seviye 7: Bitsel VEYA |
|
||||
* Seviye 6: Mantıksal VE &&
|
||||
* Seviye 5: Mantıksal VEYA ||
|
||||
* Seviye 4: Ternary ?
|
||||
* Seviye 3: Ternary else :
|
||||
* Seviye 2: Atama = += -= vb.
|
||||
* Seviye 1 (en düşük): Virgül ,
|
||||
* ================================================================ */
|
||||
|
||||
// Seviye 1 (18): Üye erişimi ve çağrı — En yüksek öncelik
|
||||
DOT, // .
|
||||
ARROW, // ->
|
||||
LBRACKET, // [
|
||||
RBRACKET, // ]
|
||||
LPAREN, // (
|
||||
RPAREN, // )
|
||||
// Seviye 18: Üye erişimi ve çağrı — En yüksek öncelik
|
||||
DOT, // . (üye erişimi) — obj.field
|
||||
// Öncelik 18. En sıkı bağlanan operatör.
|
||||
ARROW, // -> (pointer üye erişimi) — ptr->field
|
||||
// C++ tarzı. Öncelik 18.
|
||||
LBRACKET, // [ (dizi/indeks erişimi başlangıcı) — a[i]
|
||||
// Açılış köşeli parantez. Öncelik 18.
|
||||
RBRACKET, // ] (dizi/indeks erişimi bitişi) — a[i]
|
||||
// Kapanış köşeli parantez. Tek başına kullanılmaz.
|
||||
LPAREN, // ( (fonksiyon çağrısı/grouping başlangıcı)
|
||||
// İki anlamı: f(args) çağrı, (expr) gruplama.
|
||||
// Öncelik 18.
|
||||
RPAREN, // ) (fonksiyon çağrısı/grouping bitişi)
|
||||
// Kapanış parantez. Tek başına kullanılmaz.
|
||||
|
||||
// Seviye 2 (17): Postfix
|
||||
PLUS_PLUS, // ++ (postfix)
|
||||
MINUS_MINUS, // -- (postfix)
|
||||
// Seviye 17: Postfix — Soldaki ifadeye sonradan uygulanan operatörler
|
||||
PLUS_PLUS, // ++ (postfix artım) — x++
|
||||
// Önce x'in değerini döndür, sonra artır.
|
||||
// Öncelik 17. Sağ birleşmeli DEĞİL.
|
||||
MINUS_MINUS, // -- (postfix azaltım) — x--
|
||||
// Önce x'in değerini döndür, sonra azalt.
|
||||
// Öncelik 17.
|
||||
|
||||
// Seviye 3 (16): Unary Prefix
|
||||
PLUS, // + (unary)
|
||||
MINUS, // - (unary)
|
||||
BANG, // ! (mantıksal değil)
|
||||
TILDE, // ~ (bitsel değil)
|
||||
// Seviye 16: Unary Prefix — Sağındaki ifadeye uygulanan tekli operatörler
|
||||
PLUS, // + (unary plus / binary toplama)
|
||||
// Unary: +x (pozitif işareti, genelde etkisiz).
|
||||
// Binary: a + b (toplama, öncelik 13).
|
||||
// Hangi anlamda kullanıldığı parse bağlamında belirlenir.
|
||||
MINUS, // - (unary minus / binary çıkarma)
|
||||
// Unary: -x (negatif yap).
|
||||
// Binary: a - b (çıkarma, öncelik 13).
|
||||
BANG, // ! (mantıksal değil) — !x
|
||||
// Örn: if (!flag) { ... }
|
||||
// Sadece prefix. Öncelik 16.
|
||||
TILDE, // ~ (bitsel değil) — ~x
|
||||
// Bitwise NOT. Sadece prefix. Öncelik 16.
|
||||
|
||||
// Seviye 4 (15): Üs alma
|
||||
STAR_STAR, // ** (Python tarzı üs)
|
||||
CARET, // ^ (bazı dillerde üs)
|
||||
// Seviye 15: Üs alma — Sağ birleşmeli
|
||||
STAR_STAR, // ** (üs alma) — a ** b = a^b
|
||||
// Python tarzı. Öncelik 15. Sağ birleşmeli.
|
||||
// 2 ** 3 ** 2 = 2 ** (3 ** 2) = 512
|
||||
CARET, // ^ (üs alma veya bitsel XOR)
|
||||
// saQut'ta varsayılan: üs alma (öncelik 15).
|
||||
// C/C++'da XOR (öncelik 8) — bağlama göre değişebilir.
|
||||
|
||||
// Seviye 5 (14): Çarpma/Bölme
|
||||
STAR, // *
|
||||
SLASH, // /
|
||||
PERCENT, // %
|
||||
// Seviye 14: Çarpma/Bölme — Sol birleşmeli
|
||||
STAR, // * (çarpma) — a * b
|
||||
// Öncelik 14.
|
||||
SLASH, // / (bölme) — a / b
|
||||
// Tamsayı bölmesi: int / int = int.
|
||||
// Ondalık bölme: float / float = float.
|
||||
PERCENT, // % (mod alma) — a % b
|
||||
// Sadece tamsayılar için.
|
||||
|
||||
// Seviye 6 (13): Toplama/Çıkarma — PLUS ve MINUS yukarıda (unary + binary)
|
||||
// Seviye 7 (12): Bitsel kaydırma
|
||||
LSHIFT, // <<
|
||||
RSHIFT, // >>
|
||||
// Seviye 13: Toplama/Çıkarma
|
||||
// PLUS ve MINUS yukarıda tanımlandı (hem unary 16 hem binary 13).
|
||||
// Pratt parser bağlama göre doğru önceliği kullanır.
|
||||
|
||||
// Seviye 8 (11): İlişkisel karşılaştırma
|
||||
LESS, // <
|
||||
LESS_EQUAL, // <=
|
||||
GREATER, // >
|
||||
GREATER_EQUAL, // >=
|
||||
// Seviye 12: Bitsel kaydırma
|
||||
LSHIFT, // << (sola kaydırma) — a << b
|
||||
// a * 2^b. Öncelik 12.
|
||||
RSHIFT, // >> (sağa kaydırma) — a >> b
|
||||
// a / 2^b (işaretli: arithmetic, işaretsiz: logical).
|
||||
|
||||
// Seviye 9 (10): Eşitlik
|
||||
EQUAL_EQUAL, // ==
|
||||
BANG_EQUAL, // !=
|
||||
// Seviye 11: İlişkisel karşılaştırma
|
||||
LESS, // < (küçüktür) — a < b
|
||||
// true/false döndürür.
|
||||
LESS_EQUAL, // <= (küçük eşittir) — a <= b
|
||||
GREATER, // > (büyüktür) — a > b
|
||||
GREATER_EQUAL, // >= (büyük eşittir) — a >= b
|
||||
|
||||
// Seviye 10 (9): Bitsel VE
|
||||
AMPERSAND, // &
|
||||
// Seviye 10: Eşitlik
|
||||
EQUAL_EQUAL, // == (eşittir) — a == b
|
||||
// Değer eşitliği. Öncelik 10.
|
||||
BANG_EQUAL, // != (eşit değildir) — a != b
|
||||
|
||||
// Seviye 11 (8): Bitsel XOR — CARET yukarıda (üs veya XOR)
|
||||
// Seviye 9: Bitsel VE
|
||||
AMPERSAND, // & (bitsel VE) — a & b
|
||||
// Bitwise AND. Öncelik 9.
|
||||
|
||||
// Seviye 12 (7): Bitsel VEYA
|
||||
PIPE, // |
|
||||
// Seviye 8: Bitsel XOR
|
||||
// ^ (CARET) yukarıda (üs olarak seviye 15'te).
|
||||
// Gelecekte XOR için ayrı token eklenebilir.
|
||||
|
||||
// Seviye 13 (6): Mantıksal VE
|
||||
AMPERSAND_AMPERSAND, // &&
|
||||
// Seviye 7: Bitsel VEYA
|
||||
PIPE, // | (bitsel VEYA) — a | b
|
||||
// Bitwise OR. Öncelik 7.
|
||||
|
||||
// Seviye 14 (5): Mantıksal VEYA
|
||||
PIPE_PIPE, // ||
|
||||
// Seviye 6: Mantıksal VE
|
||||
AMPERSAND_AMPERSAND, // && (mantıksal VE) — a && b
|
||||
// Kısa devre (short-circuit): a false ise b değerlendirilmez.
|
||||
// Öncelik 6.
|
||||
|
||||
// Seviye 15 (4): Üçlü koşul (ternary)
|
||||
TERNARY, // ?
|
||||
COLON, // : (ternary ve etiket için)
|
||||
// Seviye 5: Mantıksal VEYA
|
||||
PIPE_PIPE, // || (mantıksal VEYA) — a || b
|
||||
// Kısa devre: a true ise b değerlendirilmez.
|
||||
// Öncelik 5.
|
||||
|
||||
// Seviye 16 (3): Atama
|
||||
EQUAL, // =
|
||||
PLUS_EQUAL, // +=
|
||||
MINUS_EQUAL, // -=
|
||||
STAR_EQUAL, // *=
|
||||
SLASH_EQUAL, // /=
|
||||
PERCENT_EQUAL, // %=
|
||||
AMPERSAND_EQUAL, // &=
|
||||
PIPE_EQUAL, // |=
|
||||
CARET_EQUAL, // ^=
|
||||
LSHIFT_EQUAL, // <<=
|
||||
RSHIFT_EQUAL, // >>=
|
||||
// Seviye 4: Üçlü koşul (ternary) — Sağ birleşmeli
|
||||
TERNARY, // ? (ternary if) — a ? b : c
|
||||
// Öncelik 4. Sağ birleşmeli.
|
||||
// a ? b : c ? d : e = a ? b : (c ? d : e)
|
||||
COLON, // : (ternary else / etiket) — ternary'in ikinci kısmı
|
||||
// Ternary'de öncelik 3 (0 değil!).
|
||||
// Ayrıca switch/case etiketleri için de kullanılır.
|
||||
|
||||
// --- Diğer Semboller ---
|
||||
LBRACE, // {
|
||||
RBRACE, // }
|
||||
SEMICOLON, // ;
|
||||
COMMA, // ,
|
||||
COLON_COLON, // ::
|
||||
// Seviye 2: Atama — Sağ birleşmeli
|
||||
EQUAL, // = (basit atama) — a = b
|
||||
// Öncelik 2. Sağ birleşmeli.
|
||||
// a = b = 5 = a = (b = 5)
|
||||
PLUS_EQUAL, // += (topla ve ata) — a += b → a = a + b
|
||||
MINUS_EQUAL, // -= (çıkar ve ata) — a -= b → a = a - b
|
||||
STAR_EQUAL, // *= (çarp ve ata) — a *= b → a = a * b
|
||||
SLASH_EQUAL, // /= (böl ve ata) — a /= b → a = a / b
|
||||
PERCENT_EQUAL, // %= (mod al ve ata) — a %= b → a = a % b
|
||||
AMPERSAND_EQUAL, // &= (bitsel VE ve ata) — a &= b → a = a & b
|
||||
PIPE_EQUAL, // |= (bitsel VEYA ve ata) — a |= b → a = a | b
|
||||
CARET_EQUAL, // ^= (XOR ve ata) — a ^= b → a = a ^ b
|
||||
LSHIFT_EQUAL, // <<= (sola kaydır ve ata) — a <<= b → a = a << b
|
||||
RSHIFT_EQUAL, // >>= (sağa kaydır ve ata) — a >>= b → a = a >> b
|
||||
|
||||
// --- Özel ---
|
||||
END_OF_FILE, // Dosya sonu
|
||||
UNKNOWN, // Bilinmeyen karakter
|
||||
COMMENT, // Yorum (// veya /* */) — şu anda token üretilmez
|
||||
PREPROCESSOR, // Önişlemci (#) — şu anda kullanılmıyor
|
||||
/* ====== Diğer Semboller ====== */
|
||||
LBRACE, // { (açılış süslü parantez) — blok başlangıcı
|
||||
// Sözdizimi: { statement1; statement2; }
|
||||
RBRACE, // } (kapanış süslü parantez) — blok bitişi
|
||||
SEMICOLON, // ; (noktalı virgül) — ifade sonu belirteci
|
||||
// C/C++/Java tarzında her ifade ; ile biter.
|
||||
COMMA, // , (virgül) — ifade ayırıcı
|
||||
// Örn: int a, b, c; veya f(1, 2, 3)
|
||||
// Öncelik 1 (en düşük).
|
||||
COLON_COLON, // :: (kapsam çözümleme) — Class::method
|
||||
// C++ tarzı. Şu anda sadece token tanımlı, parse yok.
|
||||
|
||||
/* ====== Özel Token'lar ====== */
|
||||
END_OF_FILE, // Dosya sonu belirteci.
|
||||
// Tokenizer dosya sonuna gelindiğinde üretir.
|
||||
// Parser'ın durma koşuludur.
|
||||
UNKNOWN, // Bilinmeyen/tanınamayan karakter.
|
||||
// Tokenizer'ın çözemediği her şey.
|
||||
// Hata raporlamada kullanılır.
|
||||
COMMENT, // Yorum token'ı (// veya /* */).
|
||||
// ŞU ANDA TOKEN ÜRETİLMEZ — tokenizer yorumları atlar.
|
||||
// Gelecekte belge yorumları (///, /** */) için kullanılabilir.
|
||||
PREPROCESSOR, // Önişlemci direktifi (#).
|
||||
// ŞU ANDA KULLANILMIYOR — C önişlemcisi yok.
|
||||
// Gelecekte #include, #define için.
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// KEYWORD_MAP — Keyword String → TokenType
|
||||
// KEYWORD_MAP — Keyword String → TokenType Dönüşüm Haritası
|
||||
// ============================================================================
|
||||
//
|
||||
// Tokenizer'ın ürettiği KeywordToken'ların token değerini (örn: "if")
|
||||
// Parser'ın anlayacağı TokenType'a (KW_IF) dönüştürür.
|
||||
// AMAÇ: Tokenizer'ın ürettiği KeywordToken'ların token değerini (örn: "if")
|
||||
// Parser'ın anlayacağı TokenType'a (KW_IF) dönüştürür.
|
||||
//
|
||||
// std::unordered_map: O(1) ortalama arama. const: derleme zamanı sabiti.
|
||||
// std::string_view: string kopyalamadan kaçınır.
|
||||
// ANAHTAR: std::string_view — keyword string'i (kopyalanmaz, salt okunur)
|
||||
// DEĞER: TokenType — Parser'ın anlayacağı anlamsal tip
|
||||
//
|
||||
// NOT: Bu harita, Tokenizer'daki keywords[] dizisi ile eşleşmelidir.
|
||||
// Birinde ekleme yapılırsa diğerine de eklenmelidir.
|
||||
// VERİ YAPISI: std::unordered_map<string_view, TokenType>
|
||||
// - O(1) ortalama arama süresi
|
||||
// - constexpr: derleme zamanı sabiti (derleyici tabloya gömer)
|
||||
// - std::string_view: string kopyalamadan kaçınır (performans)
|
||||
//
|
||||
// BOYUT: ~60 girdi (tüm keyword'ler)
|
||||
// NEDEN unordered_map, neden map değil?
|
||||
// - Arama sıklığı: her token için bir kez
|
||||
// - unordered_map O(1) vs map O(log n) — fark küçük ama var
|
||||
// - Sıralı erişim gerekmez
|
||||
//
|
||||
// SENKRONİZASYON UYARISI:
|
||||
// Bu harita, Tokenizer'daki keywords[] dizisi İLE EŞLEŞMELİDİR.
|
||||
// Birinde ekleme yapılırsa diğerine de eklenmelidir.
|
||||
// TODO: İki listeyi ortak bir kaynaktan üretecek bir makro/kod üreteci.
|
||||
//
|
||||
inline const std::unordered_map<std::string_view, TokenType> KEYWORD_MAP = {
|
||||
// --- Control flow ---
|
||||
|
|
@ -359,16 +486,30 @@ inline const std::unordered_map<std::string_view, TokenType> KEYWORD_MAP = {
|
|||
};
|
||||
|
||||
// ============================================================================
|
||||
// OPERATOR_MAP — Operatör/Delimiter String → TokenType
|
||||
// OPERATOR_MAP — Operatör/Delimiter String → TokenType Dönüşüm Haritası
|
||||
// ============================================================================
|
||||
//
|
||||
// Tokenizer'ın ürettiği OperatorToken ve DelimiterToken'ları TokenType'a
|
||||
// dönüştürür. Her iki token tipi de aynı haritayı kullanır çünkü parser
|
||||
// seviyesinde delimiter'lar da operatör gibi işlenir.
|
||||
// AMAÇ: Tokenizer'ın ürettiği OperatorToken ve DelimiterToken'ları TokenType'a
|
||||
// dönüştürür. Her iki token tipi de aynı haritayı kullanır çünkü
|
||||
// Parser seviyesinde delimiter'lar da operatör gibi işlenir.
|
||||
//
|
||||
// SIRALAMA ÖNEMLİ DEĞİL (unordered_map).
|
||||
// Ama Tokenizer'daki operators[] ve delimiters[] dizilerindeki sıralama
|
||||
// önemlidir — çok karakterliler önce gelmelidir.
|
||||
// ANAHTAR: std::string_view — operatör/delimiter string'i (örn: "+", "->", "{")
|
||||
// DEĞER: TokenType — Parser'ın anlayacağı anlamsal tip
|
||||
//
|
||||
// VERİ YAPISI: std::unordered_map<string_view, TokenType>
|
||||
// - O(1) ortalama arama
|
||||
// - const: derleme zamanı sabiti
|
||||
// - Boyut: ~40 girdi
|
||||
//
|
||||
// NEDEN İKİ AYRI HARİTA DEĞİL (operator + delimiter)?
|
||||
// - Parser seviyesinde fark yok: {, }, ; hepsi operatör gibi işlenir.
|
||||
// - Tek harita = tek arama = daha basit kod.
|
||||
//
|
||||
// SIRALAMA UYARISI:
|
||||
// Bu haritada sıralama önemli DEĞİL (unordered_map).
|
||||
// ANCAK Tokenizer'daki operators[] ve delimiters[] dizilerindeki
|
||||
// sıralama ÖNEMLİDİR — çok karakterliler önce gelmelidir!
|
||||
// Örn: "->" önce, "-" sonra kontrol edilmelidir.
|
||||
//
|
||||
inline const std::unordered_map<std::string_view, TokenType> OPERATOR_MAP = {
|
||||
// --- 2 karakterli ---
|
||||
|
|
@ -428,12 +569,21 @@ inline const std::unordered_map<std::string_view, TokenType> OPERATOR_MAP = {
|
|||
};
|
||||
|
||||
// ============================================================================
|
||||
// OPERATOR_MAP_REV — TokenType → Operatör String (Log için)
|
||||
// OPERATOR_MAP_REV — TokenType → Operatör String (Log/Görüntüleme İçin)
|
||||
// ============================================================================
|
||||
//
|
||||
// AST ağacını konsola yazdırırken (log) TokenType enum değerini insan
|
||||
// tarafından okunabilir operatör sembolüne dönüştürür.
|
||||
// Örn: TokenType::PLUS → "+"
|
||||
// AMAÇ: TokenType enum değerini insan tarafından okunabilir operatör
|
||||
// sembolüne dönüştürür. Log çıktısı ve hata mesajları için kullanılır.
|
||||
//
|
||||
// ANAHTAR: TokenType — enum değeri (örn: TokenType::PLUS)
|
||||
// DEĞER: std::string_view — operatör sembolü (örn: "+")
|
||||
//
|
||||
// KULLANIM:
|
||||
// auto it = OPERATOR_MAP_REV.find(type);
|
||||
// if (it != OPERATOR_MAP_REV.end()) std::cout << it->second;
|
||||
//
|
||||
// NOT: TokenType::IDENTIFIER, NUMBER, STRING, KW_* ve özel token'lar
|
||||
// bu haritada YOKTUR (operatör değiller). Onlar için ayrı dönüşüm gerekir.
|
||||
//
|
||||
inline const std::unordered_map<TokenType, std::string_view> OPERATOR_MAP_REV = {
|
||||
{TokenType::ARROW, "->"},
|
||||
|
|
@ -486,11 +636,24 @@ inline const std::unordered_map<TokenType, std::string_view> OPERATOR_MAP_REV =
|
|||
};
|
||||
|
||||
// ============================================================================
|
||||
// OPERATOR_MAP_STRREV — TokenType → Enum İsmi (Log için)
|
||||
// OPERATOR_MAP_STRREV — TokenType → Enum İsmi (Debug/Log İçin)
|
||||
// ============================================================================
|
||||
//
|
||||
// AST log çıktısında operatörün enum ismini gösterir.
|
||||
// Örn: TokenType::PLUS → "PLUS"
|
||||
// AMAÇ: AST log çıktısında operatörün enum ismini (string olarak) gösterir.
|
||||
// OPERATOR_MAP_REV'den farkı: sembol yerine enum adı döndürür.
|
||||
//
|
||||
// KULLANIM:
|
||||
// AST dump/debug çıktısı: TokenPrecedence(PLUS) yerine "PLUS(13)" gösterimi.
|
||||
//
|
||||
// ANAHTAR: TokenType — enum değeri (örn: TokenType::PLUS)
|
||||
// DEĞER: std::string_view — enum ismi (örn: "PLUS")
|
||||
//
|
||||
// ÖRN: TokenType::PLUS → "PLUS"
|
||||
// TokenType::PLUS_EQUAL → "PLUS_EQUAL"
|
||||
//
|
||||
// NOT: İki harita da (REV ve STRREV) aynı anahtarları içerir ama farklı değerler.
|
||||
// REV: "+" (operatör sembolü)
|
||||
// STRREV: "PLUS" (enum ismi)
|
||||
//
|
||||
inline const std::unordered_map<TokenType, std::string_view> OPERATOR_MAP_STRREV = {
|
||||
{TokenType::ARROW, "ARROW"},
|
||||
|
|
@ -543,40 +706,50 @@ inline const std::unordered_map<TokenType, std::string_view> OPERATOR_MAP_STRREV
|
|||
};
|
||||
|
||||
// ============================================================================
|
||||
// TokenPrecedence — Operatör Öncelik Tablosu
|
||||
// TokenPrecedence — Operatör Öncelik Tablosu (Pratt Parser'ın Kalbi)
|
||||
// ============================================================================
|
||||
//
|
||||
// Pratt parser'ın kalbi. Her TokenType için bir öncelik seviyesi döndürür.
|
||||
// Yüksek sayı = daha sıkı bağlanma (daha yüksek öncelik).
|
||||
// AMAÇ: Her TokenType için bir öncelik seviyesi döndürür.
|
||||
// Yüksek sayı = daha sıkı bağlanma (önce işlenir).
|
||||
//
|
||||
// PARAMETRE: type — sorgulanan token tipi
|
||||
// DÖNÜŞ: uint16_t — öncelik seviyesi (0-18)
|
||||
// KARMAŞIKLIK: O(1) — switch/case (derleyici jump table üretir)
|
||||
//
|
||||
// KULLANIM:
|
||||
// uint16_t prec = TokenPrecedence(current.type);
|
||||
// if (prec >= minPrec) { parseLeftDenotation(left); }
|
||||
//
|
||||
// ÖNCELİK SEVİYELERİ (yüksekten düşüğe):
|
||||
// 18: Üye erişimi . -> [ ] ( )
|
||||
// 18: Üye erişimi . -> [ ] ( ) — En yüksek
|
||||
// 17: Postfix ++ --
|
||||
// 16: Unary prefix ! ~
|
||||
// 15: Üs alma ** ^
|
||||
// 16: Unary prefix ! ~ + -
|
||||
// 15: Üs alma ** ^ — Sağ birleşmeli
|
||||
// 14: Çarpma/Bölme * / %
|
||||
// 13: Toplama/Çıkarma + -
|
||||
// 12: Bitsel kaydırma << >>
|
||||
// 11: İlişkisel < <= > >=
|
||||
// 10: Eşitlik == !=
|
||||
// 9: Bitsel VE &
|
||||
// 8: Bitsel XOR ^ (üs olarak 15'te de var — bağlama göre)
|
||||
// 8: Bitsel XOR ^ (şu anda üs olarak 15'te)
|
||||
// 7: Bitsel VEYA |
|
||||
// 6: Mantıksal VE &&
|
||||
// 5: Mantıksal VEYA ||
|
||||
// 4: Ternary ?
|
||||
// 3: Ternary else :
|
||||
// 2: Atama = += -= vb.
|
||||
// 2: Atama = += -= vb. — Sağ birleşmeli
|
||||
// 1: Virgül ,
|
||||
// 0: Önceliksiz (değerler, EOF, bilinmeyen)
|
||||
//
|
||||
// NOT: C/C++'da ^ operatörü bitsel XOR'tur (seviye 8), ama Python'da üs (seviye 15).
|
||||
// saQut'ta ^ hem üs hem XOR olarak kullanılabilir (AST'de bağlam belirler).
|
||||
// Şimdilik ^ seviye 15 (üs) olarak ayarlı.
|
||||
// KARAR: Neden ^ (CARET) seviye 15 (üs) olarak ayarlı?
|
||||
// - C/C++'da ^ bitsel XOR'tur (seviye 8).
|
||||
// - Python'da ** üs, ^ XOR'tur.
|
||||
// - saQut'ta ^ varsayılan olarak üs alma olarak kullanılır.
|
||||
// - Gelecekte XOR için ayrı token (CARET_CARET ^^) eklenebilir.
|
||||
//
|
||||
// BUG FIX (commit 438bc0e): Seviye 8'deki ölü kod (CARET için case olmadan
|
||||
// return 8) temizlendi. CARET zaten seviye 15'te STAR_STAR ile birlikte
|
||||
// işleniyor.
|
||||
// BUG FIX (commit 438bc0e):
|
||||
// Seviye 8'de CARET için ölü kod (case olmadan return 8) vardı.
|
||||
// Temizlendi. CARET zaten seviye 15'te STAR_STAR ile birlikte işleniyor.
|
||||
//
|
||||
inline uint16_t TokenPrecedence(TokenType type) {
|
||||
switch (type) {
|
||||
|
|
@ -677,18 +850,29 @@ inline uint16_t TokenPrecedence(TokenType type) {
|
|||
}
|
||||
|
||||
// ============================================================================
|
||||
// RightAssociative — Sağdan Sola Birleşme Kontrolü
|
||||
// RightAssociative — Sağdan Sola Birleşme (Associativity) Kontrolü
|
||||
// ============================================================================
|
||||
//
|
||||
// Hangi operatörler sağdan sola birleşir?
|
||||
// AMAÇ: Bir operatörün sağdan sola mı, yoksa soldan sağa mı birleştiğini
|
||||
// belirler. Pratt parser'da doğru ağaç yapısını oluşturmak için kritik.
|
||||
//
|
||||
// PARAMETRE: type — sorgulanan operatör tipi
|
||||
// DÖNÜŞ: bool — true: sağ birleşmeli, false: sol birleşmeli
|
||||
// KARMAŞIKLIK: O(1) — switch/case
|
||||
//
|
||||
// Sağ birleşmeli operatörler (a OP b OP c = a OP (b OP c)):
|
||||
// - Üs alma: **, ^ (matematiksel: 2^3^2 = 2^(3^2) = 2^9 = 512)
|
||||
// - Atama: =, +=, -=, vb. (a = b = 5 → a = (b = 5))
|
||||
// - Ternary: ?: (a ? b : c ? d : e → a ? b : (c ? d : e))
|
||||
// - STAR_STAR (üs alma): 2 ** 3 ** 2 = 2 ** (3 ** 2) = 2^9 = 512
|
||||
// (matematiksel kural: üs sağdan sola birleşir)
|
||||
// - CARET (üs alma): 2 ^ 3 ^ 2 = 2 ^ (3 ^ 2) = 512
|
||||
// - EQUAL (atama): a = b = 5 → a = (b = 5)
|
||||
// (önce b = 5 çalışır, sonra a = b)
|
||||
// - +=, -=, *=, vb. (birleşik atama): a += b += 5 → a += (b += 5)
|
||||
// - TERNARY (üçlü koşul): a ? b : c ? d : e → a ? b : (c ? d : e)
|
||||
// (iç içe ternary'lerde sağdan sola)
|
||||
//
|
||||
// Sol birleşmeli operatörler (a OP b OP c = (a OP b) OP c):
|
||||
// - Tüm diğerleri: +, -, *, /, ==, &&, vb.
|
||||
// - Tüm diğerleri: +, -, *, /, ==, &&, ||, vb.
|
||||
// (a + b + c = (a + b) + c, yani önce a+b, sonuç + c)
|
||||
//
|
||||
inline bool RightAssociative(TokenType type) {
|
||||
switch (type) {
|
||||
|
|
@ -713,49 +897,100 @@ inline bool RightAssociative(TokenType type) {
|
|||
}
|
||||
|
||||
// ============================================================================
|
||||
// ParserToken — Parser'ın Kullandığı Token Yapısı
|
||||
// ParserToken — Parser'ın Kullandığı Token Yapısı (Köprü)
|
||||
// ============================================================================
|
||||
//
|
||||
// Tokenizer'ın ürettiği ham Token ile Parser'ın ihtiyaç duyduğu anlamsal
|
||||
// tipi (TokenType) bir arada tutar.
|
||||
// AMAÇ: Tokenizer'ın ürettiği ham Token ile Parser'ın ihtiyaç duyduğu
|
||||
// anlamsal tipi (TokenType) bir arada tutar. İki katman arasında
|
||||
// köprü görevi görür.
|
||||
//
|
||||
// ALANLAR:
|
||||
// token (Token*): Tokenizer'dan gelen orijinal token. Neden pointer?
|
||||
// Çünkü Token polimorfik bir sınıf hiyerarşisidir. Değer kopyası (Token)
|
||||
// object slicing'e neden olur — alt sınıf verileri (NumberToken.isFloat,
|
||||
// StringToken.context) kaybolur.
|
||||
// BUG FIX (commit 40579ca): Eskiden Token token (değer) tutuyordu.
|
||||
//
|
||||
// type (TokenType): Token'ın anlamsal tipi. Örn: NUMBER, PLUS, KW_IF.
|
||||
// token (Token*):
|
||||
// Tokenizer'dan gelen orijinal token'a pointer.
|
||||
// Neden pointer, neden değer (Token token) değil?
|
||||
//
|
||||
// Çünkü Token polimorfik bir sınıf hiyerarşisidir:
|
||||
// Token (base)
|
||||
// +-- NumberToken (isFloat, numberValue alanları)
|
||||
// +-- StringToken (context alanı)
|
||||
// +-- IdentifierToken
|
||||
// +-- OperatorToken
|
||||
// +-- DelimiterToken
|
||||
// +-- KeywordToken
|
||||
//
|
||||
// Değer kopyası (Token token) OBJECT SLICING'e neden olur:
|
||||
// NumberToken → Token'a kopyalanırken isFloat, numberValue KAYBOLUR.
|
||||
//
|
||||
// BUG FIX (commit 40579ca):
|
||||
// Eskiden "Token token" (değer) olarak tanımlanmıştı.
|
||||
// NumberToken.isFloat her zaman false dönüyordu çünkü slicing oluyordu.
|
||||
// "Token* token" (pointer) olarak değiştirildi.
|
||||
//
|
||||
// type (TokenType):
|
||||
// Token'ın anlamsal tipi. Örn: NUMBER, PLUS, KW_IF.
|
||||
// Tokeni parselerken parseToken() tarafından atanır.
|
||||
//
|
||||
// METOTLAR:
|
||||
// is(TokenType): Bu token belirtilen tipte mi?
|
||||
// is({...}): Bu token listedeki tiplerden biri mi?
|
||||
// getPowerOperator(): Bu token bir operatör ise önceliğini döndür.
|
||||
// isRightAssociative(): Bu operatör sağ birleşmeli mi?
|
||||
// is(TokenType): Tek tip kontrolü (O(1))
|
||||
// is(initializer_list): Çoklu tip kontrolü (O(k), k = liste boyutu)
|
||||
// getPowerOperator(): Öncelik sorgulama (O(1), TokenPrecedence'a yönlendirir)
|
||||
// isRightAssociative(): Birleşme yönü sorgulama (O(1))
|
||||
//
|
||||
struct ParserToken {
|
||||
Token* token = nullptr; // Tokenizer'dan gelen orijinal token
|
||||
TokenType type = TokenType::SVR_VOID; // Anlamsal tip
|
||||
/* ====== Alanlar ====== */
|
||||
|
||||
// Tek tip kontrolü
|
||||
// Tokenizer'dan gelen orijinal token pointer'ı.
|
||||
// nullptr olabilir mi? Hayır — geçerli bir token her zaman vardır.
|
||||
// SVR_VOID durumunda token nullptr olabilir (EOF sinyali).
|
||||
Token* token = nullptr;
|
||||
|
||||
// Token'ın anlamsal tipi.
|
||||
// Varsayılan: SVR_VOID (geçersiz/başlangıç değeri).
|
||||
// parseToken() tarafından atanır.
|
||||
TokenType type = TokenType::SVR_VOID;
|
||||
|
||||
/* ====== Kolaylık Metotları ====== */
|
||||
|
||||
// is() — Tek tip kontrolü
|
||||
// PARAMETRE: t — sorgulanan token tipi
|
||||
// DÖNÜŞ: true — bu token t tipinde
|
||||
// KARMAŞIKLIK: O(1)
|
||||
// KULLANIM: if (current.is(TokenType::SEMICOLON)) { ... }
|
||||
bool is(TokenType t) const {
|
||||
return type == t;
|
||||
}
|
||||
|
||||
// Çoklu tip kontrolü — örn: is({KW_INT, KW_FLOAT, KW_VOID})
|
||||
// is() — Çoklu tip kontrolü
|
||||
// PARAMETRE: types — kontrol edilecek tipler listesi
|
||||
// DÖNÜŞ: true — bu token listedeki tiplerden birine aitse
|
||||
// KARMAŞIKLIK: O(k) — k = liste boyutu
|
||||
// KULLANIM:
|
||||
// if (current.is({KW_INT, KW_FLOAT, KW_VOID})) { ... }
|
||||
// if (current.is({TokenType::SEMICOLON, TokenType::RPAREN})) { ... }
|
||||
bool is(std::initializer_list<TokenType> types) const {
|
||||
for (TokenType t : types)
|
||||
if (type == t) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Operatör önceliği (Pratt parser için)
|
||||
// getPowerOperator() — Operatör önceliği sorgulama (Pratt parser için)
|
||||
// DÖNÜŞ: uint16_t — öncelik seviyesi (0-18)
|
||||
// KARMAŞIKLIK: O(1) — TokenPrecedence'a yönlendirir
|
||||
// KULLANIM:
|
||||
// uint16_t prec = current.getPowerOperator();
|
||||
// while (prec >= minPrec) { ... parseLeftDenotation(left); }
|
||||
uint16_t getPowerOperator() const {
|
||||
return TokenPrecedence(type);
|
||||
}
|
||||
|
||||
// Sağ birleşmeli mi?
|
||||
// isRightAssociative() — Birleşme yönü sorgulama
|
||||
// DÖNÜŞ: true — sağ birleşmeli (atama, üs, ternary)
|
||||
// false — sol birleşmeli (toplama, çarpma, vb.)
|
||||
// KARMAŞIKLIK: O(1) — RightAssociative'a yönlendirir
|
||||
// KULLANIM:
|
||||
// bool rightAssoc = current.isRightAssociative();
|
||||
// uint16_t nextPrec = rightAssoc ? prec : prec + 1;
|
||||
bool isRightAssociative() const {
|
||||
return RightAssociative(type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,176 @@
|
|||
#include "tokenizer/tokenizer.hpp"
|
||||
|
||||
std::vector<Token*> Tokenizer::scan(std::string input) {
|
||||
std::vector<Token*> tokens;
|
||||
hmx.setSourceText("", input);
|
||||
while (true) {
|
||||
Token* token = scope();
|
||||
if (token->token == "EOL") break;
|
||||
tokens.push_back(token);
|
||||
if (hmx.isEnd()) break;
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
Token* Tokenizer::scope() {
|
||||
hmx.skipWhiteSpace();
|
||||
|
||||
if (hmx.include("//", true)) { skipOneLineComment(); return scope(); }
|
||||
if (hmx.include("/*", true)) { skipMultiLineComment(); return scope(); }
|
||||
|
||||
if (hmx.isEnd()) {
|
||||
Token* t = new Token();
|
||||
t->token = "EOL";
|
||||
return t;
|
||||
}
|
||||
|
||||
if (hmx.getchar() == '"')
|
||||
return readString();
|
||||
|
||||
if (hmx.isNumeric()) {
|
||||
INumber lem = hmx.readNumeric();
|
||||
NumberToken* nt = new NumberToken();
|
||||
nt->loc = lem.startLoc;
|
||||
nt->base = lem.base;
|
||||
nt->start = lem.start;
|
||||
nt->end = lem.end;
|
||||
nt->hasEpsilon = lem.hasEpsilon;
|
||||
nt->isFloat = lem.isFloat;
|
||||
nt->token = lem.token;
|
||||
return nt;
|
||||
}
|
||||
|
||||
for (const auto& kw : keywords) {
|
||||
if (hmx.include(std::string(kw), false)) {
|
||||
char next = hmx.getchar(static_cast<int>(kw.size()));
|
||||
if ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') ||
|
||||
(next >= '0' && next <= '9') || next == '_' || next == '$') {
|
||||
continue;
|
||||
}
|
||||
KeywordToken* kt = new KeywordToken();
|
||||
kt->start = hmx.getOffset();
|
||||
kt->loc = hmx.getLocation();
|
||||
hmx.toChar(static_cast<int>(kw.size()));
|
||||
kt->end = hmx.getOffset();
|
||||
kt->token = kw;
|
||||
return kt;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& del : delimiters) {
|
||||
if (hmx.include(std::string(del), false)) {
|
||||
DelimiterToken* dt = new DelimiterToken();
|
||||
dt->start = hmx.getOffset();
|
||||
dt->loc = hmx.getLocation();
|
||||
hmx.toChar(static_cast<int>(del.size()));
|
||||
dt->end = hmx.getOffset();
|
||||
dt->token = del;
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& op : operators) {
|
||||
if (hmx.include(std::string(op), false)) {
|
||||
OperatorToken* ot = new OperatorToken();
|
||||
ot->start = hmx.getOffset();
|
||||
ot->loc = hmx.getLocation();
|
||||
hmx.toChar(static_cast<int>(op.size()));
|
||||
ot->end = hmx.getOffset();
|
||||
ot->token = op;
|
||||
return ot;
|
||||
}
|
||||
}
|
||||
|
||||
return readIdentifier();
|
||||
}
|
||||
|
||||
IdentifierToken* Tokenizer::readIdentifier() {
|
||||
hmx.beginPosition();
|
||||
IdentifierToken* it = new IdentifierToken();
|
||||
it->start = hmx.getOffset();
|
||||
|
||||
while (!hmx.isEnd()) {
|
||||
char c = hmx.getchar();
|
||||
bool read = false;
|
||||
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
|
||||
read = true;
|
||||
it->token.push_back(c);
|
||||
} else if (c == '_' || c == '$') {
|
||||
read = true;
|
||||
it->token.push_back(c);
|
||||
}
|
||||
|
||||
if (read) {
|
||||
hmx.nextChar();
|
||||
} else {
|
||||
if (it->token.empty()) { hmx.nextChar(); } break;
|
||||
}
|
||||
}
|
||||
|
||||
it->end = hmx.getOffset();
|
||||
it->size = static_cast<int>(it->context.size());
|
||||
it->loc = hmx.sourceFile.offsetToLocation(it->start);
|
||||
hmx.acceptPosition();
|
||||
return it;
|
||||
}
|
||||
|
||||
StringToken* Tokenizer::readString() {
|
||||
hmx.beginPosition();
|
||||
StringToken* st = new StringToken();
|
||||
bool started = false;
|
||||
bool ended = false;
|
||||
st->start = hmx.getOffset();
|
||||
|
||||
while (!hmx.isEnd()) {
|
||||
char c = hmx.getchar();
|
||||
st->token.push_back(c);
|
||||
switch (c) {
|
||||
case '"':
|
||||
if (!started) {
|
||||
started = true;
|
||||
} else {
|
||||
ended = true;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
hmx.nextChar();
|
||||
c = hmx.getchar();
|
||||
st->token.push_back(c);
|
||||
st->context.push_back(c);
|
||||
break;
|
||||
default:
|
||||
st->context.push_back(c);
|
||||
break;
|
||||
}
|
||||
hmx.nextChar();
|
||||
if (ended) break;
|
||||
}
|
||||
|
||||
st->end = hmx.getOffset();
|
||||
st->size = static_cast<int>(st->context.size());
|
||||
st->loc = hmx.sourceFile.offsetToLocation(st->start);
|
||||
hmx.acceptPosition();
|
||||
return st;
|
||||
}
|
||||
|
||||
void Tokenizer::skipOneLineComment() {
|
||||
while (!hmx.isEnd()) {
|
||||
if (hmx.getchar() == '\n') {
|
||||
hmx.nextChar();
|
||||
hmx.skipWhiteSpace();
|
||||
return;
|
||||
}
|
||||
hmx.nextChar();
|
||||
}
|
||||
}
|
||||
|
||||
void Tokenizer::skipMultiLineComment() {
|
||||
while (!hmx.isEnd()) {
|
||||
if (hmx.include("*/", true)) {
|
||||
hmx.skipWhiteSpace();
|
||||
return;
|
||||
}
|
||||
hmx.nextChar();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,466 +1,60 @@
|
|||
// ============================================================================
|
||||
// saQut Compiler — Tokenizer (Token Seviyesinde Tarayıcı)
|
||||
// ============================================================================
|
||||
//
|
||||
// DİZİN: src/tokenizer/tokenizer.hpp
|
||||
// KATMAN: Katman 2 — Lexer üzerine kurulu
|
||||
// BAĞIMLI: Lexer (src/lexer/lexer.hpp)
|
||||
// KULLANAN: Parser (src/parser/parser.hpp), ParserToken (src/parser/token.hpp)
|
||||
//
|
||||
// AMAÇ:
|
||||
// Lexer tarafından sağlanan karakter akışını alıp anlamlı token'lara dönüştürür.
|
||||
// Token'lar derleyicinin "kelime"leridir — parser'ın anlayacağı en küçük birim.
|
||||
//
|
||||
// Üretilen token tipleri (6 adet polimorfik sınıf):
|
||||
// ┌─────────────────┬──────────────────────────────────┐
|
||||
// │ Sınıf │ Örnek token'lar │
|
||||
// ├─────────────────┼──────────────────────────────────┤
|
||||
// │ NumberToken │ 42, 0xFF, 3.14, 1e10 │
|
||||
// │ StringToken │ "merhaba", "satır\niki" │
|
||||
// │ OperatorToken │ +, -, *, /, ==, !=, ++, -- │
|
||||
// │ DelimiterToken │ (, ), {, }, [, ], ;, ,, ., -> │
|
||||
// │ KeywordToken │ if, for, while, int, void │
|
||||
// │ IdentifierToken │ x, myVar, _private │
|
||||
// └─────────────────┴──────────────────────────────────┘
|
||||
//
|
||||
// ADR-004: Neden Polimorfik Token Sınıfları?
|
||||
// Seçenek 1 — Tagged union (std::variant): Tüm veriyi tek struct'ta
|
||||
// +: Bellek tek parça, cache-friendly
|
||||
// -: Tip eklemek için union'ı değiştirmek gerek
|
||||
// Seçenek 2 — Class hierarchy (seçilen): Base Token, alt sınıflar
|
||||
// +: Yeni token tipi eklemek kolay (yeni sınıf türet)
|
||||
// +: Her token kendi verisini taşır (NumberToken.isFloat, StringToken.context)
|
||||
// -: Heap tahsisi (new) gerektirir
|
||||
// -: virtual destructor çağrısı (maliyet: 1 vtable lookup)
|
||||
//
|
||||
// Karar: Class hierarchy. Derleyici gibi bir araçta kod netliği ve
|
||||
// genişletilebilirlik, mikro-performanstan daha önemlidir.
|
||||
//
|
||||
// TASARIM KARARLARI:
|
||||
// 1. Tablolar (operators, delimiters, keywords): constexpr std::string_view dizileri.
|
||||
// Derleme zamanında sabit, heap tahsisi yok. Sıralama önceliği:
|
||||
// - Önce keyword'ler: if/for/while gibi kelimeler identifier'lardan önce yakalanmalı
|
||||
// - Sonra delimiter'lar: -> ve :: gibi 2 karakterliler önce, tek karakterliler sonra
|
||||
// - Sonra operator'ler: != ve == gibi 2 karakterliler önce, tek karakterliler sonra
|
||||
// - En son identifier: yukarıdakilerden hiçbirine uymayan her şey
|
||||
//
|
||||
// 2. Keyword boundary check: "do" keyword'ü "double" ile karışmasın diye,
|
||||
// keyword eşleşmesinden sonraki karakter kontrol edilir. Sonraki karakter
|
||||
// harf/rakam/_/$ ise bu bir keyword değil, identifier'dır.
|
||||
//
|
||||
// 3. scope() metodu: Her çağrıldığında bir sonraki token'ı döndürür.
|
||||
// EOF'da "EOL" isimli özel bir token döndürür (Token tipi, özel değil).
|
||||
// Bu, boş token listesi sorununu çözer (parser her zaman bir token görür).
|
||||
//
|
||||
// 4. Yorum satırları: // (tek satır) ve /* */ (çok satırlı) desteklenir.
|
||||
// Yorumlar token üretmez, sessizce atlanır.
|
||||
// NOT: İç içe /* */ yorumları desteklenmez (C standardı gibi).
|
||||
//
|
||||
// BİLİNEN SINIRLAMALAR (TODO):
|
||||
// TODO: String escape sequence'leri tam değil (\x, \u, \U eksik)
|
||||
// TODO: Char literal: 'a' formatı okunamıyor
|
||||
// TODO: Raw string: R"(...)" formatı yok
|
||||
// TODO: Token konum bilgisi (satır/sütun) token'lara eklenmeli
|
||||
// TODO: Bellek sızıntısı: Token'lar heap'te new ile oluşturuluyor, silme sorumluluğu çağıranda
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef SAQUT_TOKENIZER
|
||||
#define SAQUT_TOKENIZER
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string_view>
|
||||
#include "lexer/lexer.hpp"
|
||||
|
||||
#include "tokenizer/token.hpp"
|
||||
|
||||
// ============================================================================
|
||||
// Token Tanıma Tabloları (Derleme Zamanı Sabitleri)
|
||||
// ============================================================================
|
||||
//
|
||||
// Bu tablolar, Tokenizer::scope() tarafından ham karakterlerden token üretmek
|
||||
// için kullanılır. constexpr std::string_view ile tanımlanmıştır, böylece
|
||||
// heap tahsisi yapılmaz ve derleme zamanında optimize edilir.
|
||||
//
|
||||
// SIRALAMA ÖNEMLİDİR!
|
||||
// scope() fonksiyonu bu tabloları sırasıyla tarar ve İLK eşleşmede durur.
|
||||
// Bu nedenle:
|
||||
// - Çok karakterli operatörler (==) tek karakterlilerden (=) ÖNCE gelmeli
|
||||
// - Çok karakterli delimiter'lar (->) tek karakterlilerden (.) ÖNCE gelmeli
|
||||
// - Keyword'ler, identifier'lardan ÖNCE kontrol edilmeli
|
||||
//
|
||||
// Mevcut sıralama: keywords → delimiters → operators → identifier (fallback)
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#include <string_view>
|
||||
|
||||
// Operatör tablosu. Çok karakterliler (==, !=, ++, +=, vb.) önce gelir.
|
||||
// NOT: Bu tablo ParserToken'daki OPERATOR_MAP ile eşleşmelidir.
|
||||
inline constexpr std::string_view operators[] = {
|
||||
// --- 2 karakterli: karşılaştırma ---
|
||||
"==", "!=", "<=", ">=", "&&", "||",
|
||||
// --- 2 karakterli: aritmetik ---
|
||||
"++", "--", "<<", ">>",
|
||||
// --- 2 karakterli: birleşik atama ---
|
||||
"+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=",
|
||||
// --- 1 karakterli: aritmetik ---
|
||||
"+", "-", "*", "/", "%", "<", ">",
|
||||
// --- 1 karakterli: bitsel/mantıksal ---
|
||||
"^", "!", "~", "&", "|",
|
||||
// --- 1 karakterli: temel atama ---
|
||||
"="
|
||||
};
|
||||
|
||||
// Delimiter tablosu. Çok karakterliler (->, ::) önce gelir.
|
||||
inline constexpr std::string_view delimiters[] = {
|
||||
"->", "::", // 2 karakterli bağlayıcılar
|
||||
"[", "]", "(", ")", "{", "}", // gruplama
|
||||
";", ",", ":", // ayırıcılar
|
||||
"." // üye erişimi
|
||||
"->", "::",
|
||||
"[", "]", "(", ")", "{", "}",
|
||||
";", ",", ":",
|
||||
"."
|
||||
};
|
||||
|
||||
// Keyword tablosu. Dilin tüm rezerve edilmiş kelimeleri.
|
||||
// Gruplandırılmıştır:
|
||||
// - Kontrol akışı: if, else, for, while, do, switch, case, vb.
|
||||
// - Tipler: void, int, float, double, char, string, bool
|
||||
// - Literal'lar: true, false, null
|
||||
// - OOP: class, interface, enum, extends, public, private, vb.
|
||||
// - Modüller: import, package
|
||||
// - C/C++ ekleri: const, extern, typedef, sizeof, auto, vb.
|
||||
//
|
||||
// BUG FIX (commit 438bc0e):
|
||||
// Eskiden tip keyword'leri bu listede yoktu. int, float gibi kelimeler
|
||||
// identifier olarak tokenize ediliyordu. Parser'da KW_INT gibi tipler
|
||||
// tanımlı olmasına rağmen tokenizer'dan gelmediği için değişken tanımlama
|
||||
// çalışmıyordu. Tüm eksik keyword'ler eklendi.
|
||||
//
|
||||
// Keyword tablosu.
|
||||
inline constexpr std::string_view keywords[] = {
|
||||
// Control flow
|
||||
"if", "else", "for", "while", "do",
|
||||
"switch", "case", "default", "break", "continue",
|
||||
"return", "try", "catch", "finally", "throw",
|
||||
"throws", "assert",
|
||||
// Types
|
||||
"void", "int", "float", "double", "char",
|
||||
"string", "bool",
|
||||
// Literals
|
||||
"true", "false", "null",
|
||||
// OOP
|
||||
"class", "struct", "interface","enum", "extends", "implements",
|
||||
"new", "public", "private", "protected",
|
||||
"static", "final", "abstract",
|
||||
// Modules
|
||||
"import", "package",
|
||||
// C/C++
|
||||
"const", "extern", "typedef", "sizeof",
|
||||
"auto", "constexpr","noexcept",
|
||||
"native", "synchronized", "volatile", "transient"
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Tokenizer — Lexer Üzerinde Token Üretici
|
||||
// ============================================================================
|
||||
//
|
||||
// Tek sorumluluğu: karakter akışından token listesi üretmek.
|
||||
// Durum bilgisi: Lexer'ı içerir (hmx), kendi durumu yok.
|
||||
//
|
||||
// KULLANIM:
|
||||
// Tokenizer tokenizer;
|
||||
// auto tokens = tokenizer.scan(sourceCode);
|
||||
// // tokens artık kullanılabilir. İş bitince:
|
||||
// for (auto* t : tokens) delete t;
|
||||
//
|
||||
class Tokenizer {
|
||||
public:
|
||||
Lexer hmx; // İç Lexer. "hmx" adı tarihsel.
|
||||
Lexer hmx;
|
||||
|
||||
std::vector<Token*> scan(std::string input);
|
||||
|
||||
private:
|
||||
Token* scope(); // Bir sonraki token'ı döndür
|
||||
IdentifierToken* readIdentifier(); // Tanımlayıcı oku
|
||||
StringToken* readString(); // String literal oku
|
||||
void skipOneLineComment(); // // yorum satırını atla
|
||||
void skipMultiLineComment(); // /* */ yorum bloğunu atla
|
||||
Token* scope();
|
||||
IdentifierToken* readIdentifier();
|
||||
StringToken* readString();
|
||||
void skipOneLineComment();
|
||||
void skipMultiLineComment();
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// GERÇEKLEME (Implementation)
|
||||
// ============================================================================
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// scan: Kaynak kodu tara, token listesi üret.
|
||||
//
|
||||
// Akış:
|
||||
// 1. Lexer'a kaynak kodu yükle
|
||||
// 2. scope() ile tek tek token oku
|
||||
// 3. "EOL" (End Of Line) token'ı gelene kadar devam et
|
||||
// 4. Token listesini döndür
|
||||
//
|
||||
// "EOL" token'ı: scope() EOF'da üretilen özel bir Token. Parser'a "bitti" sinyali.
|
||||
// Neden nullptr değil? Çünkü scope() her zaman geçerli bir pointer döndürmeli,
|
||||
// aksi takdirde null kontrolü gerekir. "EOL" ile bu kontrol token tipine indirgenir.
|
||||
//
|
||||
// TODO: std::unique_ptr veya std::vector<std::unique_ptr<Token>> ile bellek yönetimi
|
||||
// --------------------------------------------------------------------------
|
||||
inline std::vector<Token*> Tokenizer::scan(std::string input) {
|
||||
std::vector<Token*> tokens;
|
||||
hmx.setSourceText("", input); // Kaynak kodu hem Lexer'a yükle hem SourceFile'ı hazırla
|
||||
while (true) {
|
||||
Token* token = scope();
|
||||
if (token->token == "EOL") break; // Dosya sonu sinyali
|
||||
tokens.push_back(token);
|
||||
if (hmx.isEnd()) break; // Güvenlik kontrolü
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// scope: Bir sonraki token'ı tanı ve döndür.
|
||||
//
|
||||
// Token tanıma sıralaması (önemli!):
|
||||
// 1. Boşlukları atla
|
||||
// 2. Yorum satırlarını atla (//, /* */)
|
||||
// 3. EOF kontrolü → "EOL" token'ı
|
||||
// 4. String literal ("...")
|
||||
// 5. Sayısal literal (0-9 ile başlayan)
|
||||
// 6. Keyword'ler (sınır kontrolü ile)
|
||||
// 7. Delimiter'lar
|
||||
// 8. Operatörler
|
||||
// 9. Identifier (fallback — yukarıdakilerden hiçbiri değilse)
|
||||
//
|
||||
// Keyword boundary check:
|
||||
// include(kw, false) ile önce eşleşme kontrolü yapılır (konum değişmez).
|
||||
// Sonra keyword'ün hemen sonrasındaki karaktere bakılır.
|
||||
// Eğer bu karakter harf/rakam/_/$ ise, bu bir keyword değil, daha uzun bir
|
||||
// identifier'ın parçasıdır. Örnek: "do" → "double"ın başlangıcı olabilir.
|
||||
//
|
||||
// BUG FIX (commit 438bc0e): Eskiden boundary check yoktu. "double" kelimesi
|
||||
// "do" + "uble" olarak iki token'a ayrılıyordu.
|
||||
// --------------------------------------------------------------------------
|
||||
inline Token* Tokenizer::scope() {
|
||||
hmx.skipWhiteSpace();
|
||||
|
||||
// Yorum satırları: sessizce atla, token üretme
|
||||
if (hmx.include("//", true)) { skipOneLineComment(); return scope(); }
|
||||
if (hmx.include("/*", true)) { skipMultiLineComment(); return scope(); }
|
||||
|
||||
// EOF kontrolü
|
||||
if (hmx.isEnd()) {
|
||||
Token* t = new Token();
|
||||
t->token = "EOL"; // Özel sinyal token'ı
|
||||
return t;
|
||||
}
|
||||
|
||||
// String literal: " ile başlar
|
||||
if (hmx.getchar() == '"')
|
||||
return readString();
|
||||
|
||||
// Sayısal literal: rakam ile başlar (isNumeric: 0-9)
|
||||
if (hmx.isNumeric()) {
|
||||
INumber lem = hmx.readNumeric();
|
||||
NumberToken* nt = new NumberToken();
|
||||
nt->loc = lem.startLoc;
|
||||
nt->base = lem.base;
|
||||
nt->start = lem.start;
|
||||
nt->end = lem.end;
|
||||
nt->hasEpsilon = lem.hasEpsilon;
|
||||
nt->isFloat = lem.isFloat;
|
||||
nt->token = lem.token;
|
||||
return nt;
|
||||
}
|
||||
|
||||
// Keyword'ler: sınır kontrolü ile tarama
|
||||
// include(kw, false) → eşleşme kontrolü yap ama konumu değiştirme
|
||||
// getchar(kw.size()) → keyword sonrası karaktere bak
|
||||
// Sonraki karakter harf/rakam/_/$ ise → bu bir keyword değil, devam et
|
||||
for (const auto& kw : keywords) {
|
||||
if (hmx.include(std::string(kw), false)) {
|
||||
char next = hmx.getchar(static_cast<int>(kw.size()));
|
||||
if ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') ||
|
||||
(next >= '0' && next <= '9') || next == '_' || next == '$') {
|
||||
continue; // Daha uzun bir identifier'ın parçası
|
||||
}
|
||||
KeywordToken* kt = new KeywordToken();
|
||||
kt->start = hmx.getOffset();
|
||||
kt->loc = hmx.getLocation();
|
||||
hmx.toChar(static_cast<int>(kw.size()));
|
||||
kt->end = hmx.getOffset();
|
||||
kt->token = kw;
|
||||
return kt;
|
||||
}
|
||||
}
|
||||
|
||||
// Delimiter'lar
|
||||
for (const auto& del : delimiters) {
|
||||
if (hmx.include(std::string(del), false)) {
|
||||
DelimiterToken* dt = new DelimiterToken();
|
||||
dt->start = hmx.getOffset();
|
||||
dt->loc = hmx.getLocation();
|
||||
hmx.toChar(static_cast<int>(del.size()));
|
||||
dt->end = hmx.getOffset();
|
||||
dt->token = del;
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
|
||||
// Operatörler
|
||||
for (const auto& op : operators) {
|
||||
if (hmx.include(std::string(op), false)) {
|
||||
OperatorToken* ot = new OperatorToken();
|
||||
ot->start = hmx.getOffset();
|
||||
ot->loc = hmx.getLocation();
|
||||
hmx.toChar(static_cast<int>(op.size()));
|
||||
ot->end = hmx.getOffset();
|
||||
ot->token = op;
|
||||
return ot;
|
||||
}
|
||||
}
|
||||
|
||||
// Identifier (fallback): hiçbir özel token tipine uymayan her şey
|
||||
return readIdentifier();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// readIdentifier: Bir tanımlayıcı (identifier) oku.
|
||||
//
|
||||
// Tanımlayıcı = harf ile başlayan, harf/rakam/_/$ ile devam eden karakter dizisi.
|
||||
// NOT: Rakam ile başlayamaz (o zaman sayı olurdu).
|
||||
//
|
||||
// Karakter seti:
|
||||
// a-z, A-Z: Latin harfleri
|
||||
// 0-9: Rakamlar (ilk karakter hariç)
|
||||
// _ (alt çizgi): Yaygın ayraç
|
||||
// $ (dolar): Java/C# uyumluluğu için
|
||||
//
|
||||
// TODO: Unicode harf desteği (Türkçe karakterler, Çince, Arapça, vb.)
|
||||
// --------------------------------------------------------------------------
|
||||
inline IdentifierToken* Tokenizer::readIdentifier() {
|
||||
hmx.beginPosition();
|
||||
IdentifierToken* it = new IdentifierToken();
|
||||
it->start = hmx.getOffset();
|
||||
|
||||
while (!hmx.isEnd()) {
|
||||
char c = hmx.getchar();
|
||||
bool read = false;
|
||||
|
||||
// Harf veya rakam kontrolü (ASCII)
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
|
||||
read = true;
|
||||
it->token.push_back(c);
|
||||
} else if (c == '_' || c == '$') {
|
||||
read = true;
|
||||
it->token.push_back(c);
|
||||
}
|
||||
|
||||
if (read) {
|
||||
hmx.nextChar();
|
||||
} else {
|
||||
if (it->token.empty()) { hmx.nextChar(); } break;
|
||||
}
|
||||
}
|
||||
|
||||
it->end = hmx.getOffset();
|
||||
it->size = static_cast<int>(it->context.size());
|
||||
it->loc = hmx.sourceFile.offsetToLocation(it->start);
|
||||
hmx.acceptPosition(); // Başarılı okuma → konumu kalıcı yap
|
||||
return it;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// readString: Bir string literal oku ("...")
|
||||
//
|
||||
// Desteklenen escape sequence'ler:
|
||||
// \" → çift tırnak
|
||||
// \\ → ters bölü
|
||||
// \n → satırsonu
|
||||
// \t → sekme
|
||||
// \r → satırbaşı
|
||||
//
|
||||
// Algoritma:
|
||||
// 1. Açılış tırnağını (" ) gör → started = true
|
||||
// 2. Karakterleri oku:
|
||||
// - \ ise → sonraki karakteri escape olarak işle, context'e ekle
|
||||
// - " ise → started zaten true, bu kapanış tırnağı → ended = true
|
||||
// - Diğer → context'e ekle
|
||||
// 3. Kapanış tırnağında dur
|
||||
//
|
||||
// token: Tüm karakterler (tırnaklar ve escape'ler dahil)
|
||||
// context: Sadece gerçek string içeriği (escape'ler çözülmüş)
|
||||
//
|
||||
// Örnek: "a\"b\\n" → token = "\"a\\\"b\\\\n\"", context = "a\"b\n"
|
||||
//
|
||||
// TODO: \xNN (hex escape), \uNNNN (Unicode), \UNNNNNNNN (geniş Unicode)
|
||||
// TODO: Çok satırlı string desteği ("""...""" veya backtick `...`)
|
||||
// --------------------------------------------------------------------------
|
||||
inline StringToken* Tokenizer::readString() {
|
||||
hmx.beginPosition();
|
||||
StringToken* st = new StringToken();
|
||||
bool started = false; // Açılış tırnağı görüldü mü?
|
||||
bool ended = false; // Kapanış tırnağı görüldü mü?
|
||||
st->start = hmx.getOffset();
|
||||
|
||||
while (!hmx.isEnd()) {
|
||||
char c = hmx.getchar();
|
||||
st->token.push_back(c);
|
||||
switch (c) {
|
||||
case '"':
|
||||
if (!started) {
|
||||
started = true; // Açılış tırnağı
|
||||
} else {
|
||||
ended = true; // Kapanış tırnağı
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
// Escape sequence: sonraki karakteri olduğu gibi al
|
||||
hmx.nextChar();
|
||||
c = hmx.getchar();
|
||||
st->token.push_back(c);
|
||||
st->context.push_back(c);
|
||||
break;
|
||||
default:
|
||||
st->context.push_back(c);
|
||||
break;
|
||||
}
|
||||
hmx.nextChar();
|
||||
if (ended) break;
|
||||
}
|
||||
|
||||
st->end = hmx.getOffset();
|
||||
st->size = static_cast<int>(st->context.size());
|
||||
st->loc = hmx.sourceFile.offsetToLocation(st->start);
|
||||
hmx.acceptPosition();
|
||||
return st;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// skipOneLineComment: // ile başlayan yorum satırını satırsonuna kadar atla
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Tokenizer::skipOneLineComment() {
|
||||
while (!hmx.isEnd()) {
|
||||
if (hmx.getchar() == '\n') {
|
||||
hmx.nextChar();
|
||||
hmx.skipWhiteSpace(); // Satırsonu sonrası boşlukları da temizle
|
||||
return;
|
||||
}
|
||||
hmx.nextChar();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// skipMultiLineComment: /* */ bloğunu atla
|
||||
// NOT: İç içe yorum blokları desteklenmez (C standardı gibi).
|
||||
// --------------------------------------------------------------------------
|
||||
inline void Tokenizer::skipMultiLineComment() {
|
||||
while (!hmx.isEnd()) {
|
||||
if (hmx.include("*/", true)) {
|
||||
hmx.skipWhiteSpace();
|
||||
return;
|
||||
}
|
||||
hmx.nextChar();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SAQUT_TOKENIZER
|
||||
Loading…
Reference in New Issue