Compare commits

...

2 Commits

Author SHA1 Message Date
saqut 03970871db chore: JsonObject builder, LiteralType enum, token.hpp doc cleanup 2026-05-27 10:53:18 +03:00
saqut 9a013c53d4 Gemini 2026-05-27 10:29:30 +03:00
55 changed files with 5680 additions and 2992 deletions

22
CMakeLists.txt Normal file
View File

@ -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)

BIN
build/.ninja_deps Normal file

Binary file not shown.

16
build/.ninja_log Normal file
View File

@ -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

360
build/CMakeCache.txt Normal file
View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,7 @@
{
"InstallScripts" :
[
"/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/cmake_install.cmake"
],
"Parallel" : false
}

View File

@ -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

View File

@ -0,0 +1 @@
# This file is generated by cmake for dependency checking of the CMakeCache.txt file

View 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:

249
build/build.ninja Normal file
View File

@ -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

66
build/cmake_install.cmake Normal file
View File

@ -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()

9
scripts/build.sh Executable file
View File

@ -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"

69
src/core/sourcefile.cpp Normal file
View File

@ -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);
}
}
}
}

View File

@ -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

346
src/lexer/lexer.cpp Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

599
src/parser/parser.cpp Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")
// 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.
// 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);
}

176
src/tokenizer/tokenizer.cpp Normal file
View File

@ -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();
}
}

View File

@ -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