Porting Guide¶
Configuration File¶
The configuration header file of the Berry interpreter is berry_conf.h. This file includes a batch of macros for configuration and defines some platform-related content.
berry_conf.h File¶
Configuration Macro Switch¶
The configuration macros introduced in this section are usually used for
compiling switches of some source codes. For the convenience of
description, we call this macro “macro switch”. For the macro switch,
“on” refers to setting the macro switch to a non-zero value, and “off”
refers to setting the value of the macro switch to 0
.
Some macro switches have multiple states, not just “on” or “off”. These macro switches are generally used for configurations with multiple options. There are also some configuration macros that are not macro switches. No matter what the value of these macros is, there will be no code and therefore will not participate in compilation. These macros are generally used to configure the quantity value.
[section::BE_DEBUG]
This macro switch is used to turn on or off the debugging function of
the interpreter itself. When the value of BE_DEBUG
is 0
,
debugging is turned off, otherwise it will be turned on. The debugging
function mentioned here refers to the debugging of the interpreter, not
the debugging function of the Berry program. The default value of
BE_DEBUG
is 0
. If you use Makefile that comes with the
interpreter project to compile, this macro switch will be turned on
automatically when you use the make debug
command.
When this macro is opened, some assertions will be turned on, and an
error message will be output when the interpreter encounters an error
that the assertion can catch. You can open BE_DEBUG
when debugging
the interpreter, and close it when compiling the release.
This macro switch configures the floating point type used by the
breal
type. When the value of the macro is 0
, the double
type will be used to implement breal
, otherwise the float
type
will be used to implement breal
. This macro switch can be turned on
in some environments with low performance or memory configuration. In
the default implementation, this macro switch is turned off.
This macro configures the implementation of the bint
type. When the
value of the macro is 0
, the int
type will be used to implement
bint
, when the value is 1
, the long
type will be used to
implement bint
, and when the value is 2
, 64 will be used ] Bit
signed integer type (__int64
under Windows, long long
on other
platforms) implements bint
. The default value of this macro is
2
. If you want to reduce memory usage, you can set this macro to
0
or 1
to enable 32-bit integer type.
This macro is used to configure runtime debugging information of Berry
code. It has 3 available values: set to 0
to turn off the output of
the file name and line number of the runtime debugging information, and
set to 1
to output the file name and line number in the runtime
debugging information, set to 2
When using uint16_t
(16-bit
integer) type to store the row number information. Its default value is
1
.
Setting this macro to 0
will not store the file name and line number
information, so the memory consumption is minimal. When set to 2
, it
consumes less memory, but if the program is too long, uint16_t
will
overflow.
This macro switch configures the function of constructing objects at compile time. Turning on this macro means that constructing objects at compile time is enabled. This macro is turned on by default. When this macro is turned on, the native objects in the standard library will be generated at compile time, and when this macro is turned off, the objects in the standard library will be built at runtime.
be_regfunc
and be_regclass
functions will be affected by this
macro. The built-in object table cannot be modified when using
compile-time object construction. At this time, these two functions
cannot register objects in the built-in scope, but register objects in
the global scope.
The objects constructed during the compile time are stored together with the code and will not occupy RAM (or the readable and writable area in the memory) resources. The construction technology during the compile time can also reduce the startup time of the interpreter, so it is recommended to open this macro. Please refer to section [section::precompiled_build] for more details on compile-time construction techniques.
This macro defines the maximum Berry stack capacity, which refers to the
number of Berry objects. When the Berry code uses more than this amount
of stack, it will stop executing the program and return an error
message. The default value of this macro is 2000
, which can be
modified according to the memory capacity of the system.
This value does not affect the memory usage of the Berry stack, because the capacity of the Berry stack is dynamically adjusted, so no matter how much it is set to, it cannot help reduce memory usage. Its main function is to terminate execution when the Berry program consumes too much stack. These programs are very likely to be incorrect, for example, recursive function calls without return conditions will continue to consume the stack.
This macro defines the minimum available space in the Berry stack, and
its default value is 10
. The native function may push a value into
the Berry stack. At this time, the stack will not automatically grow, so
make sure that there is enough space in the stack for the native
function to use. It is not recommended to modify this value, but to use
the be_stack_require
function where more stack space is really
needed.
In order to detect stack overflow errors when debugging the interpreter,
you can open the BE_DEBUG
macro (section [section::BE_DEBUG]).
When this macro is opened, the short string object will save the hash value of the string to improve the running speed, but the size of each string object will increase by 4 bytes. This macro is turned off by default, and the current tests have not found that opening this macro will bring significant improvement.
This macro switch is used to enable or disable the string
module,
which is turned on by default.
This macro switch is used to enable or disable the json
module,
which is turned on by default.
This macro switch is used to enable or disable the math
module,
which is turned on by default.
This macro switch is used to enable or disable the time
module,
which is turned on by default.
This macro switch is used to enable or disable the os
module, which
is turned on by default.
This macro determines the abort
function used internally by the
Berry interpreter. By default or when the macro is not defined, the
abort
function in the C standard library will be used. This macro is
defined as abort
by default. If the user needs to explicitly specify
the abort
function used by the interpreter, then replace the macro
definition with the function required by the user. This function should
be in the same form as the abort
function declaration in the
standard library.
This macro determines the exit
function used internally by the Berry
interpreter. By default or when the macro is not defined, the exit
function in the C standard library will be used. This macro is defined
as exit
by default. If the user needs to explicitly specify the
exit
function used by the interpreter, then replace the macro
definition with the function required by the user. This function should
be in the same form as the exit
function declaration in the standard
library.
This macro determines the malloc
function used internally by the
Berry interpreter. By default or when the macro is not defined, the
malloc
function in the C standard library will be used. This macro
is defined as malloc
by default. If the user needs to explicitly
specify the function malloc
used by the interpreter, then replace
the macro definition with the function required by the user. This
function should be in the same form as the malloc
function
declaration in the standard library.
This macro determines the free
function used internally by the Berry
interpreter. By default or when the macro is not defined, the free
function in the C standard library will be used. This macro is defined
as free
by default. If the user needs to explicitly specify the
free
function used by the interpreter, then replace the macro
definition with the function required by the user. This function should
be in the same form as the free
function declaration in the standard
library.
This macro determines the realloc
function used internally by the
Berry interpreter. By default or when the macro is not defined, the
realloc
function in the C standard library will be used. This macro
is defined as realloc
by default. If the user needs to explicitly
specify the realloc
function used by the interpreter, then replace
the macro definition with the function required by the user. This
function should be in the same form as the realloc
function
declaration in the standard library.
This macro is used to define the implementation of the assertion
function. By default, the assert
function in the C standard library
is used to implement the assertion. If the target system is inconvenient
to use the assert()
function in the standard library to make an
assertion, you can modify the definition of the be_assert
macro. A
correct assertion function should use the following declaration:
void assert(int condition);
Among them, condition
is the assertion condition. If the condition
is not met, an error message will be output and the program will be
terminated. Of course, the “assert” function is usually implemented
using a macro.
berry_port.c File¶
This file implements the low-level IO functions of the Berry interpreter, including standard input and output and file system support. The berry_port.c file in the default directory contains a set of portable IO support. File operations and standard input and output are implemented using APIs in the C standard library. Path and folder operations support both Windows and POSIX standard APIs. This file also implements a set of FatFs-based IO operation functions for users to use directly. If you need to use the Berry interpreter in other environments, then these functions must be implemented separately (may only need to be implemented partially).
This section will introduce the functions of the functions implemented in the berry_port.c file and guide users to implement their own version.
void be_writebuffer(const char *buffer, size_t length);
Output a piece of data to the standard output device, the parameter
buffer
is the first address of the output data block, and length
is the length of the output data block. This function outputs to the
stdout
file by default. Inside the interpreter, this function is
usually used as a character stream output, not a binary stream.
be_writebuffer
Functions are very versatile and must be implemented.
char* be_readstring(char *buffer, size_t size);
Input a piece of data from the standard input device, and read at most
one row of data each time this function is called. The parameter
buffer
is the data buffer passed in by the caller, and the capacity
of the buffer is size
. This function will stop reading and return
when the buffer capacity is used up, otherwise it will return when a
newline character or end of file character is read. If the function
executes successfully, it will directly use the buffer
parameter as
the return value, otherwise it will return NULL
.
This function will add the read line breaks to the read data, and each
time the be_readstring
function is called, it will continue to read
from the current position. This function is only called in the
implementation of the native function input
, and the
be_readstring
function may not be implemented when it is not
necessary.
void* be_fopen(const char *filename, const char *modes);
To open a file, filename
is the name of the file to be opened, and
modes
is the opening method. The function will return a file handle
or a pointer to the file operation structure. The usage of this function
is similar to the fopen
function in the C standard library. The file
name is a C-style string (ending with a \0
character), and the
pattern should at least support the following conditions:
r
,rt
: To open a text file in read-only mode, the file must exist.r+
,rt+
: Open a text file in read-write mode, and create a new file if the file does not exist.rb
: Open a binary file in read-only mode, the file must exist.rb+
: Open a binary file in read-write mode, and create a new file if the file does not exist.w
,wt
: Create and open a text file in write-only mode, and the existing file will be deleted.w+
,wt+
: Create and open a text file in read-write mode, and the existing file will be deleted.wb
: Create and open a binary file in write-only mode, and the existing file will be deleted.wb+
: Create and open a binary file in read-write mode, and the existing file will be deleted.
By default, the fopen
function in the C standard library is used to
implement be_fopen
. If you use other methods to achieve, you should
ensure that the above operating modes can be achieved. If no file
operations are required, this function can be left blank. The file
operations here include all scenarios such as using the open
function in the script, loading the script from a file (using the
be_loadfile
function), etc.
int be_fclose(void *hfile);
Close a file, hfile
is the closed file handle. The function of this
function is similar to the function fclose
in the C standard
library.
size_t be_fwrite(void *hfile, const void *buffer, size_t length);
Write a piece of data to the specified file. Parameter hfile
is the
file handle to be written, buffer
is the pointer of the data to be
written, length
is the number of data to be written (in bytes).
size_t be_fread(void *hfile, void *buffer, size_t length);
Read a piece of data from the specified file. The parameter hfile
is
the file handle to be read, buffer
is the pointer to the read
buffer, and length
is the number of bytes to be read.
char* be_fgets(void *hfile, void *buffer, int size);
Read a line from the file, similar to the fgets
function in the C
standard library. Parameter hfile
is the file handle to be read,
buffer
is the pointer of the read buffer, and size
is the
capacity of the read buffer. This function will return when size - 1
bytes, newline characters and end of file characters are read, and the
return value is buffer
.
int be_fseek(void *hfile, long offset);
Set the position of the file read and write pointer. The parameter
hfile
is the file handle to be operated, and offset
is the value
to be set.
long int be_ftell(void *hfile);
Get the current read and write pointer of the file, the parameter
hfile
is the handle of the file to be operated, and the return value
of this function is the read and write pointer of the file.
long int be_fflush(void *hfile);
Write the data in the file buffer to the file. Parameter hfile
is
the file to be operated.
size_t be_fsize(void *hfile);
Get the size of the file. Parameter hfile
is the file to be
operated.