Charm (programming language)

Charm is a computer programming language devised in the early 1990s with similarities to the RTL/2, Pascal and C languages in addition to containing some unique features of its own. The Charm language is defined by a context-free grammar amenable to being processed by recursive descent parser as described in seminal books on compiler design.
A set of Charm tools including a compiler, assembler and linker released for the Acorn market has been reviewed in Acorn User magazine under the category of programming software. Charm reworked for RISC OS platforms has subsequently been reviewed in Archive magazine.
Charm is further described in the e-book "Programming in Charm on the Raspberry Pi".
Grammar.
The definition of the Charm grammar in Backus–Naur form along with descriptive examples of Charm constructs is defined on the Charm language page.
The language is block structured, with each block being introduced by a language keyword that is descriptive of the operation being performed in the block e.g. for, while, repeat ("iteration"), case, if ("selection"). Each block is enclosed by { and } delimiters. Additionally language lines within a block are normally indented for clarity, though this not required as white space is ignored.
Each grammatically conforming text represents a collection of executable code and associated data which can be used by a Charm tool set as a component when assembling a program that can be run under an operating system utilising the services it provides to do useful work such as data processing or interacting with users through a graphical user interface (GUI).
Data types.
Charm is a strongly typed language, but does allow some implicit conversions between numeric and floating point types. The following basic variable types are supported:
Data aggregates of the same type may be declared and statically initialised using the array keyword, and these may be multidimensional. Aggregates of different types may be declared using the record keyword, and it is allowable for such a declaration to define a union of record fields that overlay each other in terms of storage allocation. Modules may also aggregate a mixture of static and dynamic data members. Instances of both records and modules (dynamic content only) can be instantiated on the stack, or on the heap via the new operator. Modules may also define a constructor ~new procedure to initialise dynamic data and corresponding ~delete deconstructor procedure to release resources in a similar manner to the C++ language.
Referencing.
Data or procedures within the scope of a module may be made global to the final application by using the export keyword. If a module wishes to reference a procedure or data from another Charm module, it does so using the import keyword. Modules may contain instance based member variables which are accessible through procedures declared with the dynamic keyword through the implicit first parameter this pointer.
References to data constructs and procedures may be made using the ref keyword. These can be dereferenced using the val keyword. When using reference variables, comparison operators are available to check whether two reference variables refer to the same item of data ( :=: ) or whether the data they point to is the same ( = ).
Example.
The original classic Hello world program written in Charm is:
 ext proc write_string (ref array char);
 module hello;
 ent proc start ();
 write_string ("Hello world");
 end_proc;
 end_module;
and the equivalent latest version following evolutionary syntactic language changes is:
 import lib.Out;
 module Hello
 export proc ~start ()
 Out.vdu.str ("Hello world"). nl();
Tool set.
Tool set implementations are expected to provide a compiler and an assembler to generate object files from Charm source code and assembler source code, which can then be linked together along with library and run time support files to generate an executable program.
At the time of writing only one Charm tool set installation is available (free of charge) for download. The tools are themselves written in the Charm language, and the source code is available under the terms of the GNU General Public License. They run on RISC OS PCs and platforms with ARM CPUs (such as the Raspberry Pi) and on emulators for RISC OS which are hosted on Windows or Linux platforms (such as RPCEmu). Code generation for hardware assisted double precision floating point operations is supported for platforms based on ARM chips that support the VFP version 2 coprocessor architecture.
Compiler.
The Charm compiler is a recursive descent single pass compiler which parses Charm source code to generate quadruples of the form result := lhs op rhs in an intermediate language that supports arithmetic, logical and flow of control operations. Data is stored in temporaries which are assigned to registers and memory locations in the back end of the compiler. Two back ends are currently in existence, one generating Motorola 68000 assembly language, and the other generating ARM architecture.
The quadruple output from the hello world example is:
 param l1$
 call write_string[proc (ref array char) void]
and the assembler output is:
 string "hello"
 xdef _start
 align
_start
 xref _write_string
 adr r0,_l1$
 bl _write_string
 address
 align
_l1$
 string "Hello world"
 direct
 end
In more recent releases of Charm, the I/O procedures have been split into their own modules In and Out. Other standard library procedures are organised into a set of records with procedure references as fields. As part of this reorganisation, the codice_1 method is now invoked through the run time library module codice_2 via static member reference codice_3 as procedure codice_4 i.e. in the hello world example above codice_5 becomes codice_6.
Assembler.
The assembler accepts instruction mnemonics, data declarations and directives and constructs an object file containing information readily understandable by the CPU of the target processor, in particular code instructions coded in binary.
Linker.
One and only one of the Charm modules linked to form an executable program must contain a procedure matching one of the signatures:
 export proc ~start ()
 export proc ~start (int argc, ref array ref array char argv)
This is analogous to the main function in the C and Java languages. Here codice_7 contains the number of parameters passed on the command line and codice_8 contains a reference to an array of codice_9 strings (one string per positional parameter in order and a terminating codice_10).
In addition, modules may optional contain static startup and shutdown procedures invoked during program startup and shutdown that match the signatures:
 export proc ~startup ()
 export proc ~shutdown ()
The linker adds any necessary header information required by the operating system in order to execute the program, and ensures the run time library assembler support code is run which sets up the run time environment (data and stack pointers) and passes control to the start procedure of the application.
A map file showing the names of all modules linked to form the program along with global data and code references is optionally produced which can be used by debuggers and profilers.