mirror of
https://github.com/Z3Prover/z3
synced 2025-11-23 06:01:26 +00:00
Add Z3_parser_context examples for C and C++
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
This commit is contained in:
parent
52b7df22cb
commit
d9499fb00b
7 changed files with 733 additions and 0 deletions
56
examples/c_parser_context/CMakeLists.txt
Normal file
56
examples/c_parser_context/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
################################################################################
|
||||||
|
# Example C parser context project
|
||||||
|
################################################################################
|
||||||
|
# NOTE: Even though this is a C project, libz3 uses C++. When using libz3
|
||||||
|
# as a static library if we don't configure this project to also support
|
||||||
|
# C++ we will use the C linker rather than the C++ linker and will not link
|
||||||
|
# the C++ standard library in resulting in a link failure.
|
||||||
|
project(Z3_C_PARSER_CONTEXT_EXAMPLE C CXX)
|
||||||
|
cmake_minimum_required(VERSION 3.4)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
find_package(Z3
|
||||||
|
REQUIRED
|
||||||
|
CONFIG
|
||||||
|
# `NO_DEFAULT_PATH` is set so that -DZ3_DIR has to be passed to find Z3.
|
||||||
|
# This should prevent us from accidentally picking up an installed
|
||||||
|
# copy of Z3. This is here to benefit Z3's build system when building
|
||||||
|
# this project. When making your own project you probably shouldn't
|
||||||
|
# use this option.
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
message(STATUS "Z3_FOUND: ${Z3_FOUND}")
|
||||||
|
message(STATUS "Found Z3 ${Z3_VERSION_STRING}")
|
||||||
|
message(STATUS "Z3_DIR: ${Z3_DIR}")
|
||||||
|
|
||||||
|
add_executable(c_parser_context_example parser_context_example.c)
|
||||||
|
target_include_directories(c_parser_context_example PRIVATE ${Z3_C_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(c_parser_context_example PRIVATE ${Z3_LIBRARIES})
|
||||||
|
|
||||||
|
option(FORCE_CXX_LINKER "Force linker with C++ linker" OFF)
|
||||||
|
if (FORCE_CXX_LINKER)
|
||||||
|
# This is a hack for avoiding UBSan linking errors
|
||||||
|
message(STATUS "Forcing use of C++ linker")
|
||||||
|
set_target_properties(c_parser_context_example
|
||||||
|
PROPERTIES
|
||||||
|
LINKER_LANGUAGE CXX
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME MATCHES "[Ww]indows")
|
||||||
|
# On Windows we need to copy the Z3 libraries
|
||||||
|
# into the same directory as the executable
|
||||||
|
# so that they can be found.
|
||||||
|
foreach (z3_lib ${Z3_LIBRARIES})
|
||||||
|
message(STATUS "Adding copy rule for ${z3_lib}")
|
||||||
|
add_custom_command(TARGET c_parser_context_example
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
$<TARGET_FILE:${z3_lib}>
|
||||||
|
$<TARGET_FILE_DIR:c_parser_context_example>
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
18
examples/c_parser_context/README
Normal file
18
examples/c_parser_context/README
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
Example demonstrating Z3_parser_context for incremental SMTLIB2 parsing.
|
||||||
|
|
||||||
|
To build the example using the Python build system, execute:
|
||||||
|
make examples
|
||||||
|
in the build directory.
|
||||||
|
|
||||||
|
This will create the executable c_parser_context_example.
|
||||||
|
|
||||||
|
To build using CMake, from the examples/c_parser_context directory:
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DZ3_DIR=<path-to-z3-build> ..
|
||||||
|
make
|
||||||
|
|
||||||
|
On Windows, you can just execute the binary.
|
||||||
|
On macOS and Linux, you must install z3 first using
|
||||||
|
sudo make install
|
||||||
|
OR update LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (macOS) with the build directory to find the Z3 shared library.
|
||||||
268
examples/c_parser_context/parser_context_example.c
Normal file
268
examples/c_parser_context/parser_context_example.c
Normal file
|
|
@ -0,0 +1,268 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2024 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
parser_context_example.c
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Example demonstrating the use of Z3_parser_context for incremental parsing.
|
||||||
|
|
||||||
|
The Z3_parser_context API allows you to parse SMTLIB2 commands incrementally,
|
||||||
|
maintaining state (declarations, assertions) between parse calls. This is useful
|
||||||
|
for interactive applications or when processing commands in chunks.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
GitHub Copilot
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#include<stdio.h>
|
||||||
|
#include<stdlib.h>
|
||||||
|
#include<z3.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief exit gracefully in case of error.
|
||||||
|
*/
|
||||||
|
void exitf(const char* message)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Error: %s.\n", message);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Simpler error handler.
|
||||||
|
*/
|
||||||
|
void error_handler(Z3_context c, Z3_error_code e)
|
||||||
|
{
|
||||||
|
printf("Error code: %d\n", e);
|
||||||
|
exitf("incorrect use of Z3");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Create a logical context with model construction enabled.
|
||||||
|
*/
|
||||||
|
Z3_context mk_context()
|
||||||
|
{
|
||||||
|
Z3_config cfg = Z3_mk_config();
|
||||||
|
Z3_set_param_value(cfg, "model", "true");
|
||||||
|
Z3_context ctx = Z3_mk_context(cfg);
|
||||||
|
Z3_del_config(cfg);
|
||||||
|
Z3_set_error_handler(ctx, error_handler);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Create a solver.
|
||||||
|
*/
|
||||||
|
Z3_solver mk_solver(Z3_context ctx)
|
||||||
|
{
|
||||||
|
Z3_solver s = Z3_mk_solver(ctx);
|
||||||
|
Z3_solver_inc_ref(ctx, s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Delete a solver.
|
||||||
|
*/
|
||||||
|
void del_solver(Z3_context ctx, Z3_solver s)
|
||||||
|
{
|
||||||
|
Z3_solver_dec_ref(ctx, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Basic example of using Z3_parser_context.
|
||||||
|
|
||||||
|
This example demonstrates:
|
||||||
|
1. Creating a parser context
|
||||||
|
2. Parsing declarations incrementally
|
||||||
|
3. Parsing assertions incrementally
|
||||||
|
4. Using the parsed formulas in a solver
|
||||||
|
*/
|
||||||
|
void parser_context_basic_example()
|
||||||
|
{
|
||||||
|
printf("\n=== Basic Parser Context Example ===\n");
|
||||||
|
|
||||||
|
Z3_context ctx = mk_context();
|
||||||
|
Z3_parser_context parser = Z3_mk_parser_context(ctx);
|
||||||
|
Z3_parser_context_inc_ref(ctx, parser);
|
||||||
|
|
||||||
|
// First, declare some constants
|
||||||
|
printf("Parsing declarations...\n");
|
||||||
|
Z3_ast_vector decls = Z3_parser_context_from_string(ctx, parser,
|
||||||
|
"(declare-const x Int)\n"
|
||||||
|
"(declare-const y Int)");
|
||||||
|
Z3_ast_vector_inc_ref(ctx, decls);
|
||||||
|
printf("Parsed %d formulas from declarations\n", Z3_ast_vector_size(ctx, decls));
|
||||||
|
Z3_ast_vector_dec_ref(ctx, decls);
|
||||||
|
|
||||||
|
// Now parse some assertions using the previously declared symbols
|
||||||
|
printf("\nParsing first set of assertions...\n");
|
||||||
|
Z3_ast_vector assertions1 = Z3_parser_context_from_string(ctx, parser,
|
||||||
|
"(assert (> x 0))\n"
|
||||||
|
"(assert (< y 10))");
|
||||||
|
Z3_ast_vector_inc_ref(ctx, assertions1);
|
||||||
|
|
||||||
|
printf("Got %d assertions:\n", Z3_ast_vector_size(ctx, assertions1));
|
||||||
|
for (unsigned i = 0; i < Z3_ast_vector_size(ctx, assertions1); i++) {
|
||||||
|
Z3_ast assertion = Z3_ast_vector_get(ctx, assertions1, i);
|
||||||
|
printf(" %s\n", Z3_ast_to_string(ctx, assertion));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse more assertions incrementally
|
||||||
|
printf("\nParsing second set of assertions...\n");
|
||||||
|
Z3_ast_vector assertions2 = Z3_parser_context_from_string(ctx, parser,
|
||||||
|
"(assert (< x y))");
|
||||||
|
Z3_ast_vector_inc_ref(ctx, assertions2);
|
||||||
|
|
||||||
|
printf("Got %d more assertion:\n", Z3_ast_vector_size(ctx, assertions2));
|
||||||
|
for (unsigned i = 0; i < Z3_ast_vector_size(ctx, assertions2); i++) {
|
||||||
|
Z3_ast assertion = Z3_ast_vector_get(ctx, assertions2, i);
|
||||||
|
printf(" %s\n", Z3_ast_to_string(ctx, assertion));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now use these assertions in a solver
|
||||||
|
printf("\nSolving the constraints...\n");
|
||||||
|
Z3_solver solver = mk_solver(ctx);
|
||||||
|
|
||||||
|
// Add all assertions to the solver
|
||||||
|
for (unsigned i = 0; i < Z3_ast_vector_size(ctx, assertions1); i++) {
|
||||||
|
Z3_solver_assert(ctx, solver, Z3_ast_vector_get(ctx, assertions1, i));
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < Z3_ast_vector_size(ctx, assertions2); i++) {
|
||||||
|
Z3_solver_assert(ctx, solver, Z3_ast_vector_get(ctx, assertions2, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
Z3_lbool result = Z3_solver_check(ctx, solver);
|
||||||
|
if (result == Z3_L_TRUE) {
|
||||||
|
printf("SAT\n");
|
||||||
|
Z3_model model = Z3_solver_get_model(ctx, solver);
|
||||||
|
Z3_model_inc_ref(ctx, model);
|
||||||
|
printf("Model:\n%s\n", Z3_model_to_string(ctx, model));
|
||||||
|
Z3_model_dec_ref(ctx, model);
|
||||||
|
} else if (result == Z3_L_FALSE) {
|
||||||
|
printf("UNSAT\n");
|
||||||
|
} else {
|
||||||
|
printf("UNKNOWN\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
del_solver(ctx, solver);
|
||||||
|
Z3_ast_vector_dec_ref(ctx, assertions2);
|
||||||
|
Z3_ast_vector_dec_ref(ctx, assertions1);
|
||||||
|
Z3_parser_context_dec_ref(ctx, parser);
|
||||||
|
Z3_del_context(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Example showing how to add custom sorts and declarations to parser context.
|
||||||
|
|
||||||
|
This demonstrates using Z3_parser_context_add_sort and Z3_parser_context_add_decl
|
||||||
|
to make external symbols available to the parser.
|
||||||
|
*/
|
||||||
|
void parser_context_custom_decls_example()
|
||||||
|
{
|
||||||
|
printf("\n=== Parser Context with Custom Declarations Example ===\n");
|
||||||
|
|
||||||
|
Z3_context ctx = mk_context();
|
||||||
|
Z3_parser_context parser = Z3_mk_parser_context(ctx);
|
||||||
|
Z3_parser_context_inc_ref(ctx, parser);
|
||||||
|
|
||||||
|
// Create a custom sort programmatically
|
||||||
|
Z3_symbol color_name = Z3_mk_string_symbol(ctx, "Color");
|
||||||
|
Z3_sort color_sort = Z3_mk_uninterpreted_sort(ctx, color_name);
|
||||||
|
|
||||||
|
// Add the sort to the parser context
|
||||||
|
printf("Adding custom sort 'Color' to parser context...\n");
|
||||||
|
Z3_parser_context_add_sort(ctx, parser, color_sort);
|
||||||
|
|
||||||
|
// Create a custom function declaration programmatically
|
||||||
|
Z3_symbol is_red_name = Z3_mk_string_symbol(ctx, "is_red");
|
||||||
|
Z3_sort bool_sort = Z3_mk_bool_sort(ctx);
|
||||||
|
Z3_func_decl is_red = Z3_mk_func_decl(ctx, is_red_name, 1, &color_sort, bool_sort);
|
||||||
|
|
||||||
|
// Add the function to the parser context
|
||||||
|
printf("Adding custom function 'is_red' to parser context...\n");
|
||||||
|
Z3_parser_context_add_decl(ctx, parser, is_red);
|
||||||
|
|
||||||
|
// Now we can parse SMTLIB2 strings that use these custom symbols
|
||||||
|
printf("\nParsing with custom symbols...\n");
|
||||||
|
Z3_ast_vector formulas = Z3_parser_context_from_string(ctx, parser,
|
||||||
|
"(declare-const c1 Color)\n"
|
||||||
|
"(declare-const c2 Color)\n"
|
||||||
|
"(assert (is_red c1))\n"
|
||||||
|
"(assert (not (is_red c2)))");
|
||||||
|
Z3_ast_vector_inc_ref(ctx, formulas);
|
||||||
|
|
||||||
|
printf("Parsed %d formulas:\n", Z3_ast_vector_size(ctx, formulas));
|
||||||
|
for (unsigned i = 0; i < Z3_ast_vector_size(ctx, formulas); i++) {
|
||||||
|
Z3_ast formula = Z3_ast_vector_get(ctx, formulas, i);
|
||||||
|
printf(" %s\n", Z3_ast_to_string(ctx, formula));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
Z3_ast_vector_dec_ref(ctx, formulas);
|
||||||
|
Z3_parser_context_dec_ref(ctx, parser);
|
||||||
|
Z3_del_context(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Example demonstrating declaration and usage patterns.
|
||||||
|
|
||||||
|
Shows how to declare symbols explicitly before using them.
|
||||||
|
*/
|
||||||
|
void parser_context_declarations_example()
|
||||||
|
{
|
||||||
|
printf("\n=== Parser Context Declarations Example ===\n");
|
||||||
|
|
||||||
|
Z3_context ctx = mk_context();
|
||||||
|
Z3_parser_context parser = Z3_mk_parser_context(ctx);
|
||||||
|
Z3_parser_context_inc_ref(ctx, parser);
|
||||||
|
|
||||||
|
// First, explicitly declare constants
|
||||||
|
printf("Explicitly declaring constants 'a' and 'b'...\n");
|
||||||
|
Z3_ast_vector decls = Z3_parser_context_from_string(ctx, parser,
|
||||||
|
"(declare-const a Int)\n"
|
||||||
|
"(declare-const b Int)");
|
||||||
|
Z3_ast_vector_inc_ref(ctx, decls);
|
||||||
|
printf("Declarations parsed successfully\n");
|
||||||
|
Z3_ast_vector_dec_ref(ctx, decls);
|
||||||
|
|
||||||
|
// Now use the declared constants
|
||||||
|
printf("\nParsing assertions using declared constants...\n");
|
||||||
|
Z3_ast_vector formulas = Z3_parser_context_from_string(ctx, parser,
|
||||||
|
"(assert (> a 5))\n"
|
||||||
|
"(assert (< b 10))");
|
||||||
|
|
||||||
|
Z3_ast_vector_inc_ref(ctx, formulas);
|
||||||
|
printf("Successfully parsed %d assertions:\n", Z3_ast_vector_size(ctx, formulas));
|
||||||
|
for (unsigned i = 0; i < Z3_ast_vector_size(ctx, formulas); i++) {
|
||||||
|
printf(" %s\n", Z3_ast_to_string(ctx, Z3_ast_vector_get(ctx, formulas, 0)));
|
||||||
|
}
|
||||||
|
Z3_ast_vector_dec_ref(ctx, formulas);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
Z3_parser_context_dec_ref(ctx, parser);
|
||||||
|
Z3_del_context(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Main function demonstrating all parser context examples.
|
||||||
|
*/
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
printf("Z3 Parser Context Examples\n");
|
||||||
|
printf("==========================\n");
|
||||||
|
printf("\nThese examples demonstrate the Z3_parser_context API,\n");
|
||||||
|
printf("which allows incremental parsing of SMTLIB2 commands.\n");
|
||||||
|
|
||||||
|
parser_context_basic_example();
|
||||||
|
parser_context_custom_decls_example();
|
||||||
|
parser_context_declarations_example();
|
||||||
|
|
||||||
|
printf("\n=== All examples completed successfully ===\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
47
examples/cpp_parser_context/CMakeLists.txt
Normal file
47
examples/cpp_parser_context/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
################################################################################
|
||||||
|
# Example C++ parser context project
|
||||||
|
################################################################################
|
||||||
|
project(Z3_CPP_PARSER_CONTEXT_EXAMPLE CXX)
|
||||||
|
cmake_minimum_required(VERSION 3.4)
|
||||||
|
find_package(Z3
|
||||||
|
REQUIRED
|
||||||
|
CONFIG
|
||||||
|
# `NO_DEFAULT_PATH` is set so that -DZ3_DIR has to be passed to find Z3.
|
||||||
|
# This should prevent us from accidentally picking up an installed
|
||||||
|
# copy of Z3. This is here to benefit Z3's build system when building
|
||||||
|
# this project. When making your own project you probably shouldn't
|
||||||
|
# use this option.
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Z3 C++ API bindings require C++11
|
||||||
|
################################################################################
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
message(STATUS "Z3_FOUND: ${Z3_FOUND}")
|
||||||
|
message(STATUS "Found Z3 ${Z3_VERSION_STRING}")
|
||||||
|
message(STATUS "Z3_DIR: ${Z3_DIR}")
|
||||||
|
|
||||||
|
add_executable(cpp_parser_context_example cpp_parser_context_example.cpp)
|
||||||
|
target_include_directories(cpp_parser_context_example PRIVATE ${Z3_CXX_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(cpp_parser_context_example PRIVATE ${Z3_LIBRARIES})
|
||||||
|
|
||||||
|
target_compile_options(cpp_parser_context_example PRIVATE ${Z3_COMPONENT_CXX_FLAGS})
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME MATCHES "[Ww]indows")
|
||||||
|
# On Windows we need to copy the Z3 libraries
|
||||||
|
# into the same directory as the executable
|
||||||
|
# so that they can be found.
|
||||||
|
foreach (z3_lib ${Z3_LIBRARIES})
|
||||||
|
message(STATUS "Adding copy rule for ${z3_lib}")
|
||||||
|
add_custom_command(TARGET cpp_parser_context_example
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
$<TARGET_FILE:${z3_lib}>
|
||||||
|
$<TARGET_FILE_DIR:cpp_parser_context_example>
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
18
examples/cpp_parser_context/README
Normal file
18
examples/cpp_parser_context/README
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
Example demonstrating Z3_parser_context for incremental SMTLIB2 parsing.
|
||||||
|
|
||||||
|
To build the example using the Python build system, execute:
|
||||||
|
make examples
|
||||||
|
in the build directory.
|
||||||
|
|
||||||
|
This will create the executable cpp_parser_context_example.
|
||||||
|
|
||||||
|
To build using CMake, from the examples/cpp_parser_context directory:
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DZ3_DIR=<path-to-z3-build> ..
|
||||||
|
make
|
||||||
|
|
||||||
|
On Windows, you can just execute the binary.
|
||||||
|
On macOS and Linux, you must install z3 first using
|
||||||
|
sudo make install
|
||||||
|
OR update LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (macOS) with the build directory to find the Z3 shared library.
|
||||||
324
examples/cpp_parser_context/cpp_parser_context_example.cpp
Normal file
324
examples/cpp_parser_context/cpp_parser_context_example.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2024 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
parser_context_example.cpp
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Example demonstrating the use of Z3_parser_context for incremental parsing.
|
||||||
|
|
||||||
|
The Z3_parser_context API allows you to parse SMTLIB2 commands incrementally,
|
||||||
|
maintaining state (declarations, assertions) between parse calls. This is useful
|
||||||
|
for interactive applications or when processing commands in chunks.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
GitHub Copilot
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <z3.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Helper class to manage Z3_parser_context lifecycle.
|
||||||
|
|
||||||
|
Since there is no C++ wrapper for Z3_parser_context in z3++.h,
|
||||||
|
this class provides RAII-style management.
|
||||||
|
*/
|
||||||
|
class parser_context {
|
||||||
|
Z3_context m_ctx;
|
||||||
|
Z3_parser_context m_parser;
|
||||||
|
|
||||||
|
public:
|
||||||
|
parser_context(Z3_context ctx) : m_ctx(ctx) {
|
||||||
|
m_parser = Z3_mk_parser_context(ctx);
|
||||||
|
Z3_parser_context_inc_ref(ctx, m_parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
~parser_context() {
|
||||||
|
Z3_parser_context_dec_ref(m_ctx, m_parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete copy constructor and assignment operator
|
||||||
|
parser_context(const parser_context&) = delete;
|
||||||
|
parser_context& operator=(const parser_context&) = delete;
|
||||||
|
|
||||||
|
operator Z3_parser_context() const { return m_parser; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Parse a string of SMTLIB2 commands.
|
||||||
|
*/
|
||||||
|
Z3_ast_vector parse_string(const char* str) {
|
||||||
|
return Z3_parser_context_from_string(m_ctx, m_parser, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Add a sort to the parser context.
|
||||||
|
*/
|
||||||
|
void add_sort(Z3_sort s) {
|
||||||
|
Z3_parser_context_add_sort(m_ctx, m_parser, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Add a function declaration to the parser context.
|
||||||
|
*/
|
||||||
|
void add_decl(Z3_func_decl f) {
|
||||||
|
Z3_parser_context_add_decl(m_ctx, m_parser, f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Helper class to manage Z3_ast_vector lifecycle.
|
||||||
|
*/
|
||||||
|
class ast_vector {
|
||||||
|
Z3_context m_ctx;
|
||||||
|
Z3_ast_vector m_vec;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ast_vector(Z3_context ctx, Z3_ast_vector vec) : m_ctx(ctx), m_vec(vec) {
|
||||||
|
Z3_ast_vector_inc_ref(ctx, vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ast_vector() {
|
||||||
|
Z3_ast_vector_dec_ref(m_ctx, m_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete copy constructor and assignment operator
|
||||||
|
ast_vector(const ast_vector&) = delete;
|
||||||
|
ast_vector& operator=(const ast_vector&) = delete;
|
||||||
|
|
||||||
|
operator Z3_ast_vector() const { return m_vec; }
|
||||||
|
|
||||||
|
unsigned size() const {
|
||||||
|
return Z3_ast_vector_size(m_ctx, m_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
Z3_ast get(unsigned i) const {
|
||||||
|
return Z3_ast_vector_get(m_ctx, m_vec, i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Basic example of using Z3_parser_context.
|
||||||
|
|
||||||
|
This example demonstrates:
|
||||||
|
1. Creating a parser context
|
||||||
|
2. Parsing declarations incrementally
|
||||||
|
3. Parsing assertions incrementally
|
||||||
|
4. Using the parsed formulas in a solver
|
||||||
|
*/
|
||||||
|
void parser_context_basic_example() {
|
||||||
|
std::cout << "\n=== Basic Parser Context Example ===" << std::endl;
|
||||||
|
|
||||||
|
Z3_config cfg = Z3_mk_config();
|
||||||
|
Z3_set_param_value(cfg, "model", "true");
|
||||||
|
Z3_context ctx = Z3_mk_context(cfg);
|
||||||
|
Z3_del_config(cfg);
|
||||||
|
|
||||||
|
{
|
||||||
|
parser_context parser(ctx);
|
||||||
|
|
||||||
|
// First, declare some constants
|
||||||
|
std::cout << "Parsing declarations..." << std::endl;
|
||||||
|
{
|
||||||
|
ast_vector decls(ctx, parser.parse_string(
|
||||||
|
"(declare-const x Int)\n"
|
||||||
|
"(declare-const y Int)"));
|
||||||
|
std::cout << "Parsed " << decls.size() << " formulas from declarations" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now parse some assertions using the previously declared symbols
|
||||||
|
std::cout << "\nParsing first set of assertions..." << std::endl;
|
||||||
|
ast_vector assertions1(ctx, parser.parse_string(
|
||||||
|
"(assert (> x 0))\n"
|
||||||
|
"(assert (< y 10))"));
|
||||||
|
|
||||||
|
std::cout << "Got " << assertions1.size() << " assertions:" << std::endl;
|
||||||
|
for (unsigned i = 0; i < assertions1.size(); i++) {
|
||||||
|
std::cout << " " << Z3_ast_to_string(ctx, assertions1.get(i)) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse more assertions incrementally
|
||||||
|
std::cout << "\nParsing second set of assertions..." << std::endl;
|
||||||
|
ast_vector assertions2(ctx, parser.parse_string(
|
||||||
|
"(assert (< x y))"));
|
||||||
|
|
||||||
|
std::cout << "Got " << assertions2.size() << " more assertion:" << std::endl;
|
||||||
|
for (unsigned i = 0; i < assertions2.size(); i++) {
|
||||||
|
std::cout << " " << Z3_ast_to_string(ctx, assertions2.get(i)) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now use these assertions in a solver
|
||||||
|
std::cout << "\nSolving the constraints..." << std::endl;
|
||||||
|
Z3_solver solver = Z3_mk_solver(ctx);
|
||||||
|
Z3_solver_inc_ref(ctx, solver);
|
||||||
|
|
||||||
|
// Add all assertions to the solver
|
||||||
|
for (unsigned i = 0; i < assertions1.size(); i++) {
|
||||||
|
Z3_solver_assert(ctx, solver, assertions1.get(i));
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < assertions2.size(); i++) {
|
||||||
|
Z3_solver_assert(ctx, solver, assertions2.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
Z3_lbool result = Z3_solver_check(ctx, solver);
|
||||||
|
if (result == Z3_L_TRUE) {
|
||||||
|
std::cout << "SAT" << std::endl;
|
||||||
|
Z3_model model = Z3_solver_get_model(ctx, solver);
|
||||||
|
Z3_model_inc_ref(ctx, model);
|
||||||
|
std::cout << "Model:\n" << Z3_model_to_string(ctx, model) << std::endl;
|
||||||
|
Z3_model_dec_ref(ctx, model);
|
||||||
|
} else if (result == Z3_L_FALSE) {
|
||||||
|
std::cout << "UNSAT" << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "UNKNOWN" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
Z3_solver_dec_ref(ctx, solver);
|
||||||
|
} // parser and vectors destructors run here
|
||||||
|
|
||||||
|
Z3_del_context(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Example showing how to add custom sorts and declarations to parser context.
|
||||||
|
|
||||||
|
This demonstrates using Z3_parser_context_add_sort and Z3_parser_context_add_decl
|
||||||
|
to make external symbols available to the parser.
|
||||||
|
*/
|
||||||
|
void parser_context_custom_decls_example() {
|
||||||
|
std::cout << "\n=== Parser Context with Custom Declarations Example ===" << std::endl;
|
||||||
|
|
||||||
|
Z3_config cfg = Z3_mk_config();
|
||||||
|
Z3_context ctx = Z3_mk_context(cfg);
|
||||||
|
Z3_del_config(cfg);
|
||||||
|
|
||||||
|
{
|
||||||
|
parser_context parser(ctx);
|
||||||
|
|
||||||
|
// Create a custom sort programmatically
|
||||||
|
Z3_symbol color_name = Z3_mk_string_symbol(ctx, "Color");
|
||||||
|
Z3_sort color_sort = Z3_mk_uninterpreted_sort(ctx, color_name);
|
||||||
|
|
||||||
|
// Add the sort to the parser context
|
||||||
|
std::cout << "Adding custom sort 'Color' to parser context..." << std::endl;
|
||||||
|
parser.add_sort(color_sort);
|
||||||
|
|
||||||
|
// Create a custom function declaration programmatically
|
||||||
|
Z3_symbol is_red_name = Z3_mk_string_symbol(ctx, "is_red");
|
||||||
|
Z3_sort bool_sort = Z3_mk_bool_sort(ctx);
|
||||||
|
Z3_func_decl is_red = Z3_mk_func_decl(ctx, is_red_name, 1, &color_sort, bool_sort);
|
||||||
|
|
||||||
|
// Add the function to the parser context
|
||||||
|
std::cout << "Adding custom function 'is_red' to parser context..." << std::endl;
|
||||||
|
parser.add_decl(is_red);
|
||||||
|
|
||||||
|
// Now we can parse SMTLIB2 strings that use these custom symbols
|
||||||
|
std::cout << "\nParsing with custom symbols..." << std::endl;
|
||||||
|
ast_vector formulas(ctx, parser.parse_string(
|
||||||
|
"(declare-const c1 Color)\n"
|
||||||
|
"(declare-const c2 Color)\n"
|
||||||
|
"(assert (is_red c1))\n"
|
||||||
|
"(assert (not (is_red c2)))"));
|
||||||
|
|
||||||
|
std::cout << "Parsed " << formulas.size() << " formulas:" << std::endl;
|
||||||
|
for (unsigned i = 0; i < formulas.size(); i++) {
|
||||||
|
std::cout << " " << Z3_ast_to_string(ctx, formulas.get(i)) << std::endl;
|
||||||
|
}
|
||||||
|
} // parser and formulas destructors run here, before Z3_del_context
|
||||||
|
|
||||||
|
Z3_del_context(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Example demonstrating a practical use case: building an interactive theorem prover.
|
||||||
|
|
||||||
|
This shows how parser_context can maintain state across multiple user interactions.
|
||||||
|
*/
|
||||||
|
void parser_context_interactive_example() {
|
||||||
|
std::cout << "\n=== Interactive Session Example ===" << std::endl;
|
||||||
|
|
||||||
|
Z3_config cfg = Z3_mk_config();
|
||||||
|
Z3_set_param_value(cfg, "model", "true");
|
||||||
|
Z3_context ctx = Z3_mk_context(cfg);
|
||||||
|
Z3_del_config(cfg);
|
||||||
|
|
||||||
|
{
|
||||||
|
parser_context parser(ctx);
|
||||||
|
Z3_solver solver = Z3_mk_solver(ctx);
|
||||||
|
Z3_solver_inc_ref(ctx, solver);
|
||||||
|
|
||||||
|
// Simulate an interactive session with multiple commands
|
||||||
|
std::cout << "Session command 1: Define the problem domain..." << std::endl;
|
||||||
|
{
|
||||||
|
ast_vector formulas(ctx, parser.parse_string(
|
||||||
|
"(declare-const a Int)\n"
|
||||||
|
"(declare-const b Int)\n"
|
||||||
|
"(declare-const c Int)"));
|
||||||
|
for (unsigned i = 0; i < formulas.size(); i++) {
|
||||||
|
Z3_solver_assert(ctx, solver, formulas.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Session command 2: Add first constraint..." << std::endl;
|
||||||
|
{
|
||||||
|
ast_vector formulas(ctx, parser.parse_string(
|
||||||
|
"(assert (= (+ a b) c))"));
|
||||||
|
for (unsigned i = 0; i < formulas.size(); i++) {
|
||||||
|
Z3_solver_assert(ctx, solver, formulas.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Session command 3: Add more constraints..." << std::endl;
|
||||||
|
{
|
||||||
|
ast_vector formulas(ctx, parser.parse_string(
|
||||||
|
"(assert (> a 0))\n"
|
||||||
|
"(assert (> b 0))\n"
|
||||||
|
"(assert (= c 10))"));
|
||||||
|
for (unsigned i = 0; i < formulas.size(); i++) {
|
||||||
|
Z3_solver_assert(ctx, solver, formulas.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\nSession command 4: Check satisfiability..." << std::endl;
|
||||||
|
Z3_lbool result = Z3_solver_check(ctx, solver);
|
||||||
|
if (result == Z3_L_TRUE) {
|
||||||
|
std::cout << "SAT - Found a solution!" << std::endl;
|
||||||
|
Z3_model model = Z3_solver_get_model(ctx, solver);
|
||||||
|
Z3_model_inc_ref(ctx, model);
|
||||||
|
std::cout << "Model:\n" << Z3_model_to_string(ctx, model) << std::endl;
|
||||||
|
Z3_model_dec_ref(ctx, model);
|
||||||
|
} else if (result == Z3_L_FALSE) {
|
||||||
|
std::cout << "UNSAT - No solution exists" << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "UNKNOWN" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
Z3_solver_dec_ref(ctx, solver);
|
||||||
|
} // parser destructors run here
|
||||||
|
|
||||||
|
Z3_del_context(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Main function demonstrating all parser context examples.
|
||||||
|
*/
|
||||||
|
int main() {
|
||||||
|
std::cout << "Z3 Parser Context Examples" << std::endl;
|
||||||
|
std::cout << "==========================" << std::endl;
|
||||||
|
std::cout << "\nThese examples demonstrate the Z3_parser_context API," << std::endl;
|
||||||
|
std::cout << "which allows incremental parsing of SMTLIB2 commands." << std::endl;
|
||||||
|
|
||||||
|
parser_context_basic_example();
|
||||||
|
parser_context_custom_decls_example();
|
||||||
|
parser_context_interactive_example();
|
||||||
|
|
||||||
|
std::cout << "\n=== All examples completed successfully ===" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -117,8 +117,10 @@ def init_project_def():
|
||||||
add_js()
|
add_js()
|
||||||
# Examples
|
# Examples
|
||||||
add_cpp_example('cpp_example', 'c++')
|
add_cpp_example('cpp_example', 'c++')
|
||||||
|
add_cpp_example('cpp_parser_context_example', 'cpp_parser_context')
|
||||||
add_cpp_example('z3_tptp', 'tptp')
|
add_cpp_example('z3_tptp', 'tptp')
|
||||||
add_c_example('c_example', 'c')
|
add_c_example('c_example', 'c')
|
||||||
|
add_c_example('c_parser_context_example', 'c_parser_context')
|
||||||
add_c_example('maxsat')
|
add_c_example('maxsat')
|
||||||
add_dotnet_example('dotnet_example', 'dotnet')
|
add_dotnet_example('dotnet_example', 'dotnet')
|
||||||
add_java_example('java_example', 'java')
|
add_java_example('java_example', 'java')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue