The Cint language
Cint accepts most of C’s expression and statement syntax, but it is an
interpreter with its own rules, not a C compiler. Programs that compile with
gcc often need small changes. This page lists what Cint accepts on this
build, what it does not, and how to print values. How to run programs is in
Cint: the C interpreter.
Program structure
A Cint file is a sequence of top-level statements: declarations, function
definitions and ordinary statements such as calls. They run in order as the
file is read, so a function must be defined before the statement that calls
it. There is no main; call your function explicitly at the end:
cint_reset();
int show_unit(int unit)
{
bcm_info_t info;
int rv;
rv = bcm_info_get(unit, &info);
if (rv != BCM_E_NONE) {
printf("bcm_info_get: %s\n", bcm_errmsg(rv));
return rv;
}
print info;
return 0;
}
show_unit(0);
printf("DONE\n");
Comments are /* … */ (which may nest) and // ….
Types and declarations
C types:
char,short,int,long,long long, theirunsignedforms, anddouble.SDK integer types:
uint8,uint16,uint32,int8,int16,int32and their_tforms, and every SDK typedef such asbcm_port_t,bcm_vlan_t,bcm_if_torbcm_gport_t.uint64, the SDK’s 64-bit counter type. It is not an ordinary integer: use theCOMPILER_64_*helpers or$nameprinting (below).SDK value types with their own printed form:
bcm_mac_t(MAC address),bcm_ip_t(IPv4 address),bcm_ip6_t(IPv6 address),bcm_pbmp_t(port bitmap).Every SDK structure (
bcm_port_info_t,bcm_l3_route_t…) and your ownstructdefinitions. Afterstruct pair { int key; int value; };the tagpairis itself a type name: declare variables aspair p;. Writingstruct pair p;is a syntax error (unexpected TYPE_NAME, expecting IDENTIFIER or '{').Arrays (with initialisers such as
int a[4] = { 1, 2, 3, 4 };), pointers, and strings (char *s = "text";).
A declaration is a statement and may appear anywhere in a block, but not
inside the parentheses of a for. Declare the loop variable first:
int i;
for (i = 0; i < 4; i++) {
printf("%d\n", i);
}
Initialise SDK structures with their _init function
(bcm_l3_egress_t_init(&egr), bcm_port_config_t_init(&cfg)) before
use, as in C.
What is not supported
C feature |
In Cint |
|---|---|
Casts such as |
Syntax error. Assign to a variable of the wanted type instead
( |
|
Not supported; |
Declarations in |
Syntax error; declare the variable before the loop. |
|
Syntax error; write |
|
Not supported. |
|
Rejected with |
The C library ( |
Not available. Use the |
|
Rejected; see Printing. |
A cast is reported at the cast, and the rest of the file does not run; the
line NEG_CAST after in this program is never printed:
Hardware-validated
drivshell> cint /root/negative_cast.c
NEG_CAST before
nc_y = (int) nc_x;
^^^ syntax error, unexpected INT [/root/negative_cast.c:12]
nc_y = (int) nc_x;
^ syntax error, unexpected ')' [/root/negative_cast.c:12]
** warning: statement with no effect
Functions
Define functions as in C, with a return type and typed parameters. A
function may take at most 16 parameters. Parameters behave as in C: pass
&var where the SDK expects a pointer for an output value.
Calls are checked against the registered prototype: the number of arguments
and each argument’s type must match, or the call fails with wrong number
of parameters or arg <n> … was wrong type. Use cint list function
<name>; to see a prototype.
Some SDK macros are available as functions: BCM_FAILURE(rv),
BCM_SUCCESS(rv), BCM_PBMP_MEMBER(&pbm, port),
BCM_PBMP_PORT_ADD(pbm, port), BCM_PBMP_COUNT(pbm, count),
BCM_GPORT_IS_TRUNK(gport), BCM_GPORT_LOCAL_GET(gport),
BCM_L3_ITF_VAL_GET(intf) and others. BCM_IF_ERROR_RETURN(expr) returns
from the current function when expr is negative.
Callbacks
SDK functions that take a callback, such as the *_traverse functions,
accept the name of a Cint function. The Cint function must have exactly the
callback’s prototype; cint list fp <name>; shows it. For example, the
route-table walk:
int route_cb(int unit, int index, bcm_l3_route_t *info, void *user_data)
{
bcm_ip_t net = info->l3a_subnet;
printf("%d: ${net} intf %d\n", index, info->l3a_intf);
return BCM_E_NONE;
}
bcm_l3_route_traverse(0, 0, 0, 19, route_cb, NULL);
Since Cint has no casts, user_data cannot be turned back into a typed
pointer. Pass NULL and keep counters or results in global variables.
While the callback runs, the SDK holds the lock of the table being walked,
so syncd cannot update that table until the walk finishes. Keep
callbacks short and limit how much they print.
Iterators
BCM_PBMP_ITER(pbm, port) { … } runs the block once for every port in a
port bitmap, as in C:
bcm_port_config_t cfg;
bcm_pbmp_t pbm;
bcm_port_t port;
bcm_port_config_t_init(&cfg);
bcm_port_config_get(0, &cfg);
pbm = cfg.port;
BCM_PBMP_ITER(pbm, port) {
printf("port %d\n", port);
}
BCM_RX_REASON_ITER and BCM_PKT_DROP_REASON_ITER work the same way
for reason sets.
Control flow
if/else, while, do … while, for, switch/case/
default, break, continue, return and the ?: operator work
as in C. Arithmetic, comparison, logical, bitwise and assignment operators
(+=, <<= …) are supported, as are &, *, ., -> and
array subscripts. sizeof takes a variable or expression, such as
sizeof(info); sizeof of a type name, such as sizeof(int), fails
at run time with invalid operand(s) to 'sizeof'. Cint checks pointers and array bounds when they
are used and reports attempt to dereference NULL pointer or array
subscript out of range instead of crashing. Pointers returned by the SDK
are not checked beyond NULL.
Self-check
language_tour.c tries the features on this page one by one and prints
LANG <name> ok or LANG <name> FAIL for each, followed by DONE
language_tour. On Trident 3 its sizeof(int) check fails, and the run
also shows what a run-time error does: the rest of lt_main() is skipped
(no further LANG lines), while the top-level statements after the call
still run:
/*
* language_tour.c - exercise the parts of the C subset described in the
* Cint language page. Read-only: calls no SDK function that changes state.
* Run: cint /root/language_tour.c
* Every check prints "LANG <name> ok" or "LANG <name> FAIL".
*/
cint_reset();
struct lt_pair {
int key;
int value;
};
int lt_check(char *name, int ok)
{
if (ok) {
printf("LANG %s ok\n", name);
} else {
printf("LANG %s FAIL\n", name);
}
return ok;
}
int lt_square(int x)
{
return x * x;
}
int lt_sum(int *values, int count)
{
int i;
int total = 0;
for (i = 0; i < count; i++) {
total += values[i];
}
return total;
}
void lt_set(int *p, int v)
{
*p = v;
}
int lt_main()
{
int a[4] = { 1, 2, 3, 4 };
int n = 0;
int i;
int x = 0;
int kind;
char buf[64];
char *s = "text";
lt_pair pair;
uint32 big = 0x80000000;
uint64 wide;
bcm_switch_control_t ctl;
lt_check("function-call", lt_square(7) == 49);
lt_check("array-arg", lt_sum(a, 4) == 10);
lt_set(&x, 42);
lt_check("pointer-out", x == 42);
pair.key = 1;
pair.value = 2;
lt_check("struct", pair.key + pair.value == 3);
print pair;
i = 0;
while (i < 3) {
i++;
}
do {
n++;
} while (n < 2);
lt_check("while-do", i == 3 && n == 2);
switch (i) {
case 3:
kind = 1;
break;
default:
kind = 0;
break;
}
lt_check("switch", kind == 1);
lt_check("ternary", (i > 2 ? 5 : 6) == 5);
lt_check("sizeof", sizeof(int) == 4);
lt_check("hex-uint32", (big >> 31) == 1);
sprintf(buf, "%s-%d", s, 7);
lt_check("sprintf", sal_strcmp(buf, "text-7") == 0);
ctl = bcmSwitchL3EgressMode;
kind = ctl;
printf("enum via int: %d\n", kind);
printf("enum via $: ${ctl}\n");
COMPILER_64_SET(&wide, 1, 2);
printf("uint64 via $: ${wide}\n");
printf("uint64 halves: hi %u lo %u\n", COMPILER_64_HI(&wide), COMPILER_64_LO(&wide));
lt_check("defined-bcm_port_info_get", cint_defined("bcm_port_info_get") == 1);
printf("cint_defined(soc_mem_search) = %d\n", cint_defined("soc_mem_search"));
printf("cint_defined(soc_reg_t) = %d\n", cint_defined("soc_reg_t"));
return 0;
}
lt_main();
print bcm_info_t;
printf("DONE language_tour\n");
Hardware-validated
drivshell> cint /root/language_tour.c
LANG function-call ok
LANG array-arg ok
LANG pointer-out ok
LANG struct ok
lt_pair pair = {
int key = 1 (0x1)
int value = 2 (0x2)
}
LANG while-do ok
LANG switch ok
LANG ternary ok
** error: invalid operand(s) to 'sizeof'
** error: invalid operand(s) to '=='
** error: error evaluating argument 2 to function 'lt_check'
struct bcm_info_t {
uint32 vendor;
uint32 device;
uint32 revision;
uint32 capability;
int num_pipes;
int num_pp_pipes;
int num_buffers;
int num_instances_per_pp_pipe;
uint32 package_rev_id;
uint32 interposer_rev_id;
int dies_num;
uint32[16] die_dev_id;
uint32[16] die_rev_id;
}
size is 172 bytes
DONE language_tour
Enums and constants
SDK enum values (bcmSwitchL3EgressMode, snmpIfHCInOctets,
BCM_E_NOT_FOUND) and constants (BCM_L3_IP6, BCM_L2_STATIC) are
known by name and can be used in expressions, comparisons and as
arguments. Enum numbers differ between SDK releases; always use the name.
An enum value is not an int for printf. To print its number, assign
it to an int first:
int n;
n = bcmSwitchL3EgressMode;
printf("bcmSwitchL3EgressMode = %d\n", n);
print bcm_switch_control_t; lists every name and number of an enum.
Passing the enum directly is a run-time error; the statement prints nothing more, and the program continues:
Hardware-validated
drivshell> cint /root/negative_enum_printf.c
NEG_ENUM before
NEG_ENUM direct ** error: printf expected integer type but received bcm_switch_control_t
NEG_ENUM via int 230
DONE negative_enum_printf
Printing
print <expression>;Prints the type, a name and the value. A variable prints under its own name, an expression as
$$. Structures print every member, nested, with integers in decimal and hexadecimal.print "text";prints the text and a newline.print <type>;prints a structure’s layout or an enum’s values.printf("format", …)C-style formatting. The format must be a string literal.
%d %i %u %x %X %o %cneed an integer argument,%sa string orchararray,%f %e %gadouble,%pa pointer. Width, precision,-andl/llwork as in C.$nameor${name}inside aprintfformatPrints the variable
namein its natural form: an enum as its name, abcm_ip_tas10.0.0.1, abcm_mac_tas00:1A:2B:3C:4D:5E(upper-case hexadecimal), abcm_pbmp_tas a list of ports, auint64as{0x<high> 0x<low>}. A plain$nameends at a space,:,.,(,),'or end of line; use${name}otherwise. Because of this, aprintfformat cannot contain a literal$followed by text.sprintf(buf, "format", …),snprintf(buf, size, "format", …)Format into a
chararray.
The cint reference shows print of a bcm_info_t captured on
an older SONiC build; Cint recipes shows the same structure on
this build, which has more members, including arrays: an array member prints
as unsigned int[16] die_dev_id = { … } with one line per element.
Broadcom’s Trident 3 examples (OpenBCM sdk-6.5.27 CINT interpreter sources (src/appl/cint, src/appl/diag/cint) and Trident 3 CINT examples with logs (src/examples/xgs/TD3)) print the
result of a function call with print; a function declared to return
bcm_error_t shows its value by name. The last lines of one such run:
Unvalidated
BCM.0> init all;cint lsr_php.c
...
execute(): Start
...
bcm_error_t $$ = BCM_E_NONE (0)
execute(): End
64-bit counters
bcm_stat_get and similar functions return uint64 values. Print them
with $name (hexadecimal high and low words) or split them:
uint64 v;
bcm_stat_get(0, 1, snmpIfHCInOctets, &v);
printf("in octets ${v} low word %u\n", COMPILER_64_LO(&v));
COMPILER_64_HI(&v) and COMPILER_64_LO(&v) return the two 32-bit
halves; COMPILER_64_SET, COMPILER_64_ADD_64, COMPILER_64_SUB_64
and COMPILER_64_IS_ZERO do arithmetic.
Return codes
SDK functions return an int: BCM_E_NONE (0) for success, a negative
BCM_E_… code for failure. bcm_errmsg(rv) returns the text. Compare
against the names, not the numbers.
Code |
Value |
|
|---|---|---|
|
0 |
Ok |
|
−1 |
Internal error |
|
−2 |
Out of memory |
|
−3 |
Invalid unit |
|
−4 |
Invalid parameter |
|
−5 |
Table empty |
|
−6 |
Table full |
|
−7 |
Entry not found |
|
−8 |
Entry exists |
|
−9 |
Operation timed out |
|
−10 |
Operation still running |
|
−11 |
Operation failed |
|
−12 |
Operation disabled |
|
−13 |
Invalid identifier |
|
−14 |
No resources for operation |
|
−15 |
Invalid configuration |
|
−16 |
Feature unavailable |
|
−17 |
Feature not initialized |
|
−18 |
Invalid port |
BCM_E_UNAVAIL usually means the API is not supported on Trident 3, not
that something is broken.