Skip to content
PaskalCPP
Language

Declarations

Constants, variables, routines, forward declarations, exported names, linkage, overloads and variadic routines. Types themselves are on Types and Objects.

declarations.pcpp
module exe declarations;

// A const always names its type; a const can bound an array
const
  CCount: int32 = 3;

var
  GSlots: array[0..CCount - 1] of int32;
  GTotal: int32 = 10;
  GZero: int32;
  GName: string = "PaskalCPP";

// IsOdd is called before its full declaration: forward makes it visible
forward routine IsOdd(AN: int32): bool;

routine IsEven(AN: int32): bool;
begin
  if AN = 0 then
    return true;
  end;
  return IsOdd(AN - 1);
end;

routine IsOdd(AN: int32): bool;
begin
  if AN = 0 then
    return false;
  end;
  return IsEven(AN - 1);
end;

// var: the caller's variable itself; const: read only
routine Bump(var AN: int32);
begin
  AN := AN + 1;
end;

routine Twice(const AN: int32): int32;
begin
  return AN * 2;
end;

// Overloads differ in their parameter types
routine Kind(AN: int32): string;
begin
  return "int32";
end;

routine Kind(AS: string): string;
begin
  return "string";
end;

routine Kind(AB: bool): string;
begin
  return "bool";
end;

// A trailing ... makes a routine variadic; varargs reads the extra arguments
routine Total(ABase: int32; ...): int64;
var
  LT: int64;
  LI: int32;
begin
  LT := ABase;
  LI := 0;
  while LI < varargs.count do
    LT := LT + varargs.get(LI, int32);
    LI := LI + 1;
  end;
  return LT;
end;

begin
  println("CCount = {}, len(GSlots) = {}", CCount, len(GSlots));
  println("GTotal = {}, GZero = {}, GName = {}", GTotal, GZero, GName);
  println("IsEven(10) = {}, IsOdd(7) = {}", IsEven(10), IsOdd(7));
  Bump(GTotal);
  println("Bump: {}", GTotal);
  println("Twice(21) = {}", Twice(21));
  println("Kind(5) = {}, Kind(\"x\") = {}, Kind(true) = {}", Kind(5), Kind("x"), Kind(true));
  println("Total(100, 1, 2, 3) = {}", Total(100, 1, 2, 3));
  // A body var is visible from its own line on
  var LInner: int32 = GTotal * 2;
  println("LInner = {}", LInner);
end.
output on x86_64-windows-gnu and x86_64-linux-gnu
CCount = 3, len(GSlots) = 3
GTotal = 10, GZero = 0, GName = PaskalCPP
IsEven(10) = true, IsOdd(7) = true
Bump: 11
Twice(21) = 42
Kind(5) = int32, Kind("x") = string, Kind(true) = bool
Total(100, 1, 2, 3) = 106
LInner = 22
[Heap] Allocs: 0, Frees: 0, Leaked: 0

Declare before use

Everything is explicit: a name is visible only after its declaration, at every level (module, routine, body, nested block). A variable, type or routine used before it is SM0002; a variable named in its own initializer is SM0001. A routine is visible in its own body, so recursion needs no forward declaration.

  • Two declarations of one name in one scope are SM0004: two module variables, two parameters, a routine's variable named like its parameter, a variable and a routine.
  • A declaration in an inner scope shadows an outer one of the same name: a routine's variable hides a module variable, a variable in an if block hides the routine's. The outer one is unchanged.
  • Names starting with pcpp_ belong to the compiler: a module, const, type, field, choice value, variable, routine, parameter or local named so is SM0017. The rule is case-sensitive (Pcpp_G is free); a name in mixed C++ is clang's to judge.

Constants

const Name: Type = value; always names its type; no type is inferred from the value, and a const with no type is PR0001.

  • A const value is a constant: a literal (a string too), an earlier const, an operator over constants, or opaque C++ such as INT_MAX, which clang judges. A variable or a routine call is SM0202.
  • The value converts to the declared type only when no value can be lost: a constant that does not fit (300 into int8, -1 into uint8) or a float for an integer const is SM0200.
  • A const stands wherever a constant is required, such as an array bound. Const blocks may stand at module level, in a routine before its begin, and as a statement in a body.

Variables

var Name: Type [= value]; declares a variable. The initializer is any expression of names declared before it, converted only when no value can be lost: an int32 into an int8 is SM0200.

  • A variable without an initializer starts as its type's zero: 0, false, an empty string, every record field and array element zero, nil for a pointer.
  • A routine's locals start over on every call; a module variable keeps its value.
  • A var statement in a body declares a variable visible from its own line on.
  • Name: Type; external; binds the C symbol of that name: at module level only (SM0302 in a routine or the main block), with no initializer (SM0301).

Routines

routine Name[(params)][: Type]; then a body. With a return type it is a function and returns with return <value>; without one it is a procedure, called as a statement. The parameter list may be left out entirely; a call still writes ().

A parameter is passed by value (a copy), var (the caller's variable itself) or const (read only); parameters are separated by ;.

  • A var argument must be a variable of exactly the parameter's type: a literal or an int64 for a var int32 is SM0405. A constant argument that does not fit a value parameter is SM0404.
  • A procedure call used as a value is SM0406; return; in a function is SM0610; a function that can reach its end without returning is SM0612 at its end.
  • A routine body holds any number of type, const and var blocks, in any order, before its begin; a method body takes only var blocks (a const block there is PR0025).

External routines

external replaces a routine's body and binds a symbol linked from elsewhere; with no library the symbol is in this build, for example a C file added with @addsourcefile.

external "lib"; or external CName; (a const string) names the library to link, as @linklibrary does; the program then needs no @linklibrary. A file name there is PR0055, a const that is not a string or a name nothing declares SM0326, a const naming a path SM0327; a library the linker cannot find is reported at the clause's library name.

Linkage

cpplink (C++ linkage, a mangled name) is the default. clink gives a routine C linkage (extern "C", its plain name), so C code can call it by name, and PaskalCPP can bind a C routine with clink and external.

linkage_clink.pcpp
module dll linkage_clink;

exported routine clink AddInts(const AA: int32; const AB: int32): int32;
begin
  return AA + AB;
end;

end.

C has no overloads: an overloaded clink routine gets C++ linkage, with the warning SM0323 on each one, and the build succeeds.

Forward declarations

forward routine ...; and forward type Name; make a name visible before its full declaration, for mutual recursion and self-referencing types.

  • The full routine must follow in the same scope and match the forward exactly: linkage, exported or not, variadic, parameter names, modes and return type each differ as SM0306. A forward routine never declared in full is SM0307; a full routine with other parameter types pairs with no forward (it is a new overload) and leaves the forward SM0307.
  • A forward type is completed by a record, object or overlay (an alias is SM0305). Until then it is used only behind ptr to (by value it is SM0300) or inside a routine type's parameter and return types. Never completed is SM0303, a forward after the full declaration SM0304.

exported

exported before a module-level declaration makes it visible to importing modules, reached as unit.Name, or bare when only one imported unit exports the name (see Modules); without it a declaration is private to its module. It covers the one declaration after it, a whole var, const or type block included, and nothing after that block.

  • A private name used by an importer is SM0006, including a private constant the unit's exported declarations are built from.
  • Exported declarations may be built from the unit's private constants and types (an array bound, an align value, a parameter type); the importer uses them all.
  • exported is module level only (PR0057 among a routine's own declarations) and precedes a PaskalCPP declaration only: before C++, cpp header;, the main block or a second exported it is PR0024. A main module may export too.

Overloads

Routines of one name in one scope are overloads when their parameter types differ, in count or in a type. Parameter names, var / const, linkage and the return type make no overload: a repeat is SM0324 at the later one.

errorSM0324…/samples/diagnostics_overload_repeat.pcpp(34,1)
'Show' is already declared with these parameter types: overloads differ in their parameter types …/samples/diagnostics_overload_repeat.pcpp(29,1): note: the first declaration of 'Show' with these parameter types

A call considers only the overloads that take its arguments by PaskalCPP's implicit conversions (a C/C++ value is taken by every one); none is SM0402, naming them all. Among those that take them, C++'s ranking picks: Kind("text") with a bool and a string overload calls the string one, and an int64 never narrows to an int32 overload.

  • A forward and its full declaration are one overload.
  • An imported unit's overloads never join the module's own set of that name: a bare call sees the module's own set (SM0404 when none of it takes the arguments), the unit's is reached qualified. One imported unit's set, with no own name of that spelling, is used bare as that set.

Variadic routines

A trailing ... (after ;) makes a routine variadic; varargs reads the extra arguments. varargs in a routine that is not variadic is SM0417.

  • cpplink (the default): every argument travels with its type. varargs.count, next(T), get(i, T), reset() and copy() are available (a varargs local holds an independent copy, cursor included), and no fixed parameter is needed. Integer literals pack as int32 (int64 when larger), float literals as float64, string literals as string. A cpplink variadic routine cannot share its name with another routine (SM0330).
  • clink: the C calling convention, so only varargs.next (varargs.count is SM0418: pass the count yourself), and a routine with a body needs a fixed parameter before ... (SM0325). An external clink routine may be declared with ... alone.