Root of ctestgen AST representation is ctestgen.generator.Program
class.
Program designed as a container for macros, enums, global variables and functions.
Structures are currently not supported.
Basis of program code is ctestgen.generator.CodeBlock
that representing C compound statement.
CodeBlock
serves as a body for functions and control structures.
Additionally API contains some utils for faster code description.
ctestgen.generator.Program
is root of AST representation, container for macros, enums, global variables and functions.
from ctestgen.generator import Program
program = Program('example_program')
Class methods:
Method | Description |
---|---|
__str__() |
Text representation of program |
set_name(name) |
Change program name |
add_include(include) |
Add include macro definition to program |
add_define(define) |
Add define macro definition to program |
add_enum(self, enum) |
Add enum definition to program |
add_global_variable |
Add global variable definition to program |
add_function |
Add function definition to program |
write_to_file(output_dir) |
Write program to file .c in defined dir |
Example:
example_program = Program('example_program')
example_program.add_include(Include('stdlib.h'))
max_define = Define('MAX(a,b)', '(a > b ? a : b)')
example_program.add_define(max_define)
example_enum = Enum(('N', 100), ('M', 10), 'G')
example_program.add_enum(example_enum)
global_const_a = ConstInt('a', 15)
example_program.add_global_variable(global_const_a)
main_function = Function('main', Int, Int('argc'), Pointer(Pointer(Char))('argv'))
var_b = Int('b')
var_max = Int('max')
var_ptr = Pointer(Int)('example_alloc_ptr')
main_body = CodeBlock(
Assignment(VarDeclaration(var_b), 1),
Assignment(var_max, max_define.process_macros(global_const_a, var_b)),
Assignment(var_ptr, malloc(Mul(SizeOf(Int), example_enum[0], example_enum[1]))),
free(var_ptr),
Return(0)
)
main_function.set_body(main_body)
example_program.add_function(main_function)
print(example_program)
Output:
#include <stdlib.h>
#define MAX(a,b) (a > b ? a : b)
enum {
N = 100,
M = 10,
G
};
const int a = 15;
int main(int argc, char** argv) {
int b = 1;
max = (a > b ? a : b);
example_alloc_ptr = malloc(sizeof(int) * N * M);
free(example_alloc_ptr);
return 0;
}
Class ctestgen.generator.CodeBlock
represents C compound statement.
{
<statement1>
...
<statementn>
}
CodeBlock
serves as a body for functions and control structures.
Class object creation takes list of statements for block.
Example:
var_a = Int('a')
var_b = Int('b')
example_block = CodeBlock(
Assignment(VarDeclaration(var_a), 10),
Assignment(VarDeclaration(var_b), 20),
Assignment(var_a, Add(var_a, var_b))
)
Output:
{
int a = 10;
int b = 20;
a = a + b;
}
Represents C function.
Example:
arguments_count = 4
sum_arguments = [Int('num_' + str(arg_idx)) for arg_idx in range(arguments_count)]
sum_function = Function('sum_' + str(arguments_count) + '_nums', Int, sum_arguments)
sum_result = Int('sum')
sum_body = CodeBlock(
Assignment(sum_result.get_declaration(), Add(sum_arguments)),
Return(sum_result)
)
sum_function.set_body(sum_body)
print(sum_function.get_declaration())
Output:
int sum_4_nums(int num_0, int num_1, int num_2, int num_3) {
int sum = num_0 + num_1 + num_2 + num_3;
return sum;
}
Class ctestgen.generator.Type
represents variable type.
Concrete types as Int
, Float
, etc is objects of Type
.
Class ctestgen.generator.Var
represents variable.
Type
is callable, it returns new Var
object with corresponding var type.
var_a = Int('a')
print(VarDeclaration(var_a))
Output:
int a
Code Int('a')
equals to Var('a', Int)
, choose what you like.
ctestgen.generator.Pointer
is subclass of Type
, and pointer variables
created in a slightly different way.
var_ptr1 = Pointer(Int)('ptr1')
var_ptr2 = Pointer(Pointer(Int))('ptr2')
var_ptr3 = Pointer(Pointer(Void))('ptr3')
print(VarDeclaration(var_ptr1))
print(VarDeclaration(var_ptr2))
print(VarDeclaration(var_ptr3))
Output:
int* ptr1
int** ptr2
void** ptr3
Array variable creation:
var_array1 = Array('A1', Int, 100, 200, 300)
array_sizes_enum = Enum(('N', 100), ('M', 200))
var_array2 = Array('A2', Int, array_sizes_enum.constants)
print(VarDeclaration(var_array1))
print(VarDeclaration(var_array2)
Output:
int A1[100][200][300]
int A1[N][M]
Code Array('A1', Int, 100, 200, 300)
equals to Array('A1', Int, [100, 200, 300])
.
Defined types:
Lib type | C type |
---|---|
Char | char |
Int | int |
UInt | unsigned int |
Long | long |
SizeT | size_t |
Float | float |
Double | double |
Void | void |
Bool | bool |
ConstChar | const char |
ConstInt | const int |
ConstUInt | const unsigned int |
ConstLong | const long |
ConstSizeT | const size_t |
ConstFloat | const float |
ConstDouble | const double |
ConstVoid | const void |
ConstBool | const bool |
Array | C array like int A[N] |
ArrayC99 | C99 array like int (*A)[N] |
You can easily define new types:
Int64 = Type('int64_t')
Class ctestgen.generator.Operator
represents C operator.
Concrete operators as Assignment
, Mul
, etc is objects of Operator
.
Operator
is callable, it returns text representation of operator call.
var_a = Float('a')
var_b = Float('b')
var_c = Float('c')
print(Mul(var_a, var_b, var_c))
Output:
a * b * c
Defined operators:
Lib operator | C operator |
---|---|
Assignment | arg0 = arg1 |
Add | arg0 + arg1 |
Sub | arg0 - arg1 |
Mul | arg0 * arg1 |
Div | arg0 / arg1 |
Modulo | arg0 % arg1 |
Increment | arg++ |
IncrementPrefix | ++arg |
Decrement | arg-- |
DecrementPrefix | --arg |
IsEqual | arg0 == arg1 |
IsNotEqual | arg0 != arg1 |
IsGreater | arg0 > arg1 |
IsGreaterOrEqual | arg0 >= arg1 |
IsLess | arg0 < arg1 |
IsLessOrEqual | arg0 <= arg1 |
Not | !arg |
And | arg0 && arg1 |
Or | arg0 || arg1 |
BitNot | ~arg0 |
BitAnd | arg0 & arg1 |
BitOr | arg0 | arg1 |
BitXor | arg0 ^ arg1 |
BitLeftShift | arg0 << arg1 |
BitRightShift | arg0 >> arg1 |
AddAssignment | arg0 += arg1 |
SubAssignment | arg0 -= arg1 |
MultAssignment | arg0 *= arg1 |
DivAssignment | arg0 /= arg1 |
ModuloAssignment | arg0 %= arg1 |
BitAndAssignment | arg0 &= arg1 |
BitOrAssignment | arg0 |= arg1 |
BitXorAssignment | arg0 ^= arg1 |
BitLeftShiftAssignment | arg0 <<= arg1 |
BitRightShiftAssignment | arg0 >>= arg1 |
Subscript | [ arg0 ] |
Indirection | *arg0 |
AddressOf | &arg0 |
StructureReference | arg0.arg1 |
StructureDereference | arg0->arg1 |
Call | ( ) |
TernaryCondition | arg0 ? arg1 : arg2 |
Conversion | (arg0) arg1 |
SizeOf | sizeof(arg0) |
Return | return arg0 |
Break | break |
Continue | continue |
You can easily define new Operator
:
AddAndMul = Operator('({args[0]} + {args[1]}) * {args[2]}')
var_a = Float('a')
var_b = Float('b')
var_c = Float('c')
print(SumAndMul(var_a, var_b, var_c))
Output:
(a + b) * c
Currently only Include
and Define
macros implemented.
Example usage:
max_define = Define('MAX(a,b)', '(a > b ? a : b)')
var_b = Float('b')
var_c = Float('c')
print(max_define.get_declaration())
print(max_define(var_b, var_c))
print(max_define.process_macros(var_b, var_c))
Output:
#include <stdlib.h>
#define MAX(a,b) (a > b ? a : b)
MAX(b, c)
(b > c ? b : c)
Class ctestgen.generator.If
represents C if
control statement.
Example:
var_a = Int('a')
condition = IsGreaterOrEqual(var_a, 0)
true_body = CodeBlock(
Assignment(var_a, 100)
)
false_body = CodeBlock(
Assignment(var_a, -100)
)
if_example = If(condition, true_body, false_body)
print(if_example)
Output:
if (a >= 0) {
a = 100;
} else {
a = -100;
}
Class ctestgen.generator.For
represents C For
loop.
Example:
var_a = Int('a')
var_i = SizeT('i')
init = Assignment(VarDeclaration(var_i), 0)
continue_condition = IsLess(var_i, 100)
step = Increment(var_i)
body = CodeBlock(
AddAssignment(var_a, 2)
)
for_example = For(init, continue_condition, step, body)
print(for_example)
Output:
for (size_t i = 0; i < 100; i++) {
a += 2;
}
Class ctestgen.generator.While
represents C while
loop.
Example:
var_a = Int('a')
continue_condition = IsLess(var_a, 33)
body = CodeBlock(
AddAssignment(var_a, 15)
)
while_example = While(continue_condition, body)
print(while_example)
Output:
while (a < 33) {
a += 15;
}
Class ctestgen.generator.ArraySubscriptTemplate
designed to
define array subscript expressions in loops. It contains templates for every
array dimension subscript expression, that defined in class object creation.
Dimension subscript expression is are defined by objects of subclasses
of abstract class ctestgen.generator.DimSubscriptTemplate
Currently implemented LinearDimSubscriptTemplate
- template for generating
expressions of form a * iter_var + b
.
Example:
dim0_template = LinearDimSubscriptTemplate(1, 0)
dim1_template = LinearDimSubscriptTemplate(0, 2)
dim2_template = LinearDimSubscriptTemplate(5, 7)
array_subscript_template = ArraySubscriptTemplate([dim0_template, dim1_template, dim2_template])
iter_var0 = Int('i')
iter_var1 = Int('j')
iter_var2 = Int('k')
var_array1 = Array('A1', Int, 100, 200, 300)
array_sizes_enum = Enum(('N', 10), ('M', 20), ('K', 30))
var_array2 = Array('A2', Int, array_sizes_enum.constants)
print(array_subscript_template.generate_subscript(var_array1, [iter_var0, iter_var1, iter_var2]))
print(array_subscript_template.generate_subscript(var_array2, [iter_var0, iter_var1, iter_var2]))
Output:
A1[i * 1][2][k * 5 + 7]
A2[i * 1][2][k * 5 + 7]
API contains shorter form for code:
dim0_template = LinearDimSubscriptTemplate(1, 0)
dim1_template = LinearDimSubscriptTemplate(0, 2)
dim2_template = LinearDimSubscriptTemplate(5, 7)
array_subscript_template = ArraySubscriptTemplate([dim0_template, dim1_template, dim2_template])
This code equals to:
array_subscript_template = ArrayLinearSubscriptTemplate([(1, 0), (0, 2), (5, 7)])
Example of usage in For
loop.
Example:
array_sizes_enum = Enum(('N', 10), ('M', 20))
var_array = Array('A', Int, array_sizes_enum.constants)
array_subscript_template = ArrayLinearSubscriptTemplate([(1, 0), (5, 7)])
iter_var0 = Int('i')
iter_var1 = Int('j')
for0_init = Assignment(VarDeclaration(iter_var0), 0)
for0_continue_condition = IsLess(iter_var0, array_sizes_enum[0])
for0_step = Increment(iter_var0)
for0_loop = For(for0_init, for0_continue_condition, for0_step)
for1_init = Assignment(VarDeclaration(iter_var1), 0)
for1_continue_condition = IsLess(iter_var1, array_sizes_enum[1])
for1_step = Increment(iter_var1)
for1_body = CodeBlock(
Assignment(array_subscript_template.generate_subscript(var_array, [iter_var0, iter_var1]), 15)
)
for1_loop = For(for1_init, for1_continue_condition, for1_step, for1_body)
for0_body = CodeBlock(for1_loop)
for0_loop.set_body(for0_body)
print(for0_loop)
Output:
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
A[i * 1][j * 5 + 7] = 15;
}
}
To simplify this, API contains function to array passing.
Function ctestgen.generator.pass_array
designed to simplify arrays passing.
Simplify the previous example:
array_sizes_enum = Enum(('N', 10), ('M', 20))
var_array = Array('A', Int, array_sizes_enum.constants)
array_subscript_template = ArrayLinearSubscriptTemplate([(1, 0), (5, 7)])
print(pass_array(var_array, array_subscript_template, assignment_source=15))
Output:
for (int i0 = 0; i0 < N; i0++) {
for (int i1 = 0; i1 < M; i1++) {
A[i0 * 1][i1 * 5 + 7] = 15;
}
}
More examples:
array_sizes_enum = Enum(('N', 10), ('M', 20), ('K', 30))
var_array = Array('A', Double, array_sizes_enum.constants)
array_subscript_template = ArrayLinearSubscriptTemplate([(1, 0), (5, 7), (0, 2)])
assignment_var = Double('s')
print(pass_array(var_array,
array_subscript_template,
assignment_source=IncrementPrefix(assignment_var)))
Output:
for (int i0 = 0; i0 < N; i0++) {
for (int i1 = 0; i1 < M; i1++) {
for (int i2 = 0; i2 < K; i2++) {
A[i0 * 1][i1 * 5 + 7][2] = ++s;
}
}
}
array_sizes_enum = Enum(('N', 10), ('M', 20), ('K', 30), ('O', 40))
var_array = Array('A', Double, array_sizes_enum.constants)
array_subscript_template = ArrayLinearSubscriptTemplate([(1, 0), (5, 7), (0, 2), (2, 2)])
assignment_var = Double('s')
print(pass_array(var_array,
array_subscript_template,
assignment_source=IncrementPrefix(assignment_var),
iter_var_type=SizeT))
Output:
for (size_t i0 = 0; i0 < N; i0++) {
for (size_t i1 = 0; i1 < M; i1++) {
for (size_t i2 = 0; i2 < K; i2++) {
for (size_t i3 = 0; i3 < O; i3++) {
A[i0 * 1][i1 * 5 + 7][2][i3 * 2 + 2] = ++s;
}
}
}
}
Function ctestgen.generator.generate_dim_sizes_names
designed to
automate array dimensions names generation.
Example:
print(generate_dim_sizes_names(2))
print(generate_dim_sizes_names(10))
Output:
['N', 'M']
['N0', 'N1', 'N2', 'N3', 'N4', 'N5', 'N6', 'N7', 'N8', 'N9']
Yoy can define enum constants with this names:
dims_count = 4
names = generate_dim_sizes_names(dims_count)
enum_constants = [(names[i], (i + 1) * 100) for i in range(dims_count)]
enum_example = Enum(enum_constants)
print(enum_example.get_declaration())
Output:
enum {
N = 100,
M = 200,
L = 300,
K = 400
};