[RFC] Symbol mangling schema

Jose E. Marchesi jemarch@gnu.org
Sun Nov 9 19:03:43 GMT 2025


> Jose and list,
>
> On Sun, Nov 9, 2025 at 10:03 AM Jose E. Marchesi <jemarch@gnu.org> wrote:
>
>>
>> Hello people!
>>
>> The implementation of modules and separated compilation is progressing
>> steadily:
>>
>>   $ cat module.a68
>>   module Foo =
>>   def int i;
>>       int j = 20;
>>       proc ticks = void: to i do puts ("tick'n") od;
>>       i := 5
>>   postlude
>>     ticks
>>   fed
>>   $ cat foo.c
>>   #include <stdio.h>
>>
>>   void __FOO_prelude (void);
>>   void __FOO_postlude (void);
>>
>>   extern void ticks (void);
>>   extern int i;
>>   extern int j;
>>
>>   void
>>   __algol68_main ()
>>   {
>>     __FOO_prelude ();
>>     ticks ();
>>     i = 3;
>>     printf ("j: %d\n", j);
>>     __FOO_postlude ();
>>   }
>>   $ ga68 -c module.a68
>>   $ gcc -c foo.c
>>   $ ga68 module.o foo.o -lga68
>>   $ ./a.out
>>   tick
>>   tick
>>   tick
>>   tick
>>   tick
>>   j: 20
>>   tick
>>   tick
>>   tick
>>
>> Now it is time to decide on a schema for mangling our symbols.  In my
>> opinion the schema shall fullfil the following desirable properties:
>>
>> - It shall be as simple and orthogonal as possible.  In particular, the
>>   meaning of symbols shall not depend on their positions.
>>
>> - It shall lead to readable (by humans) and predictable symbol names.
>>   It shouldn't be necessary for a programmer to use a tool in order to
>>   figure out the mangled symbol for some given construct.  For example,
>>   it is immediate to figure out that the symbol corresponding to an
>>   identifier "accountant" defined in a module "Foo" is FOO_accountant.
>>
>> - The mangling schema shall be as much as compiler-independent as
>>   possible.
>>
>> So this is my proposal:
>>
>> 1. Symbols used internally do not follow any fixed mangling rule.
>>
>> 2. The main program symbol is __algol68_main.
>>
>> 3. Bold words, i.e. mode indicants, module indicants and operator
>>    indicants are mangled to upper-case letters and normal digits.  Note
>>    that the underscores following taggles supported by the stropping
>>    regimes are not part of the indicants, and therefore are not conveyed
>>    to mangled symbols.  For example, a mode "Tree_Node" is mangled to
>>    TREENODE.
>>
>> 4. Tags, i.e. identifiers, are mangled to lower-case and normal digits.
>>    Again, underscores following taggles are not part of the tag proper,
>>    and are not conveyed to mangled symbols.  Fo example, the identifier
>>    "remove_row" is mangled to removerow.
>>
>> 5. Symbols corresponding to publicized identifiers and indicants always
>>    start with the name of the definition module publicizing them,
>>    followed by an underscore character.  For example, in the module:
>>
>>      module Json =
>>      def
>>          pub mode JSON_Val = union
>> (void,bool,int,string.JSON_Arr,JSON_Obj),
>>          pub mode JSON_Arr = struct (JSON_Elm elements),
>>          ...;
>>
>>          pub proc json_new_obj = JSON_Val: heap JSON_Obj;
>>          ...
>>      fed
>>
>>    The mode JSON_Val will mangle to a symbol JSON_JSONVAL.
>>    The identifier json_new_obj will mangle to a symbol JSON_jsonnewobj.
>>
>> 6. Publicized symbols that are intended to be used by the compiler or
>>    runtime are preceded by the mangled name of the module followed by
>>    two underscore characters.  For example, the prelude and postlude for
>>    the above module will be accessible via the mangled symbols
>>    JSON__prelude and JSON__postlude.
>>
>> 7. Operator symbols, the monads and nomads, are mangled to letter codes
>>    symbolizing the symbols:
>>
>>      %    (p)ercentage
>>      ^    (c)aret
>>      &    (a)mpersand
>>      +    (p)lus
>>      -    (m)inus
>>      ~    (t)ilde
>>      !    (b)ang
>>      ?    (q)uestion mark
>>      >    bi(g)ger than
>>      <    (l)ess than
>>      /    (s)lash
>>      =    (e)qual
>>      :    c(o)lon
>>      *    sta(r)
>>
>>    Each letter code is followed by a single underscore character.  So
>>    for example, in the following module:
>>
>>      module Foo =
>>      def
>>          int ss;
>>          op // = (int a, b) int: a + b;
>>          ...
>>      fed
>>
>>    The identifier ss will mangle to a symbol FOO_ss.
>>    The operator // will mangle to a symbol FOO_s_s_.
>>
>> And that's basically it.
>> WDYT?
>>
>
> A quick read and my general reaction is that the above seems both thorough
> and reasonable; but it leads me to a question that might be only indirectly
> connected to mangling:
>
> How do operator priorities defined in a module get communicated to the
> users of the module?  Do they somehow become an intrinsic part of the
> operator once defined, and are therefore exported (or not) according to
> whether the operator is exported (or not)?

The module interface emitted in the .a68_exports section contain
extracts (records) for both operators and operator priorities.  So for
example for something like:

  module Foo = def op ELEMS = ...; prio ELEMS = 8; .. fed

The emitted interface for Foo will contain:

	.byte	0x4	# operator extract
	.value	0x6	# opname
	.string	"ELEMS"
	.long	.M23	# mode
	.long	0	# mdextra size

        [...]

	.byte	0x3	# prio extract
	.value	0x6	# opname
	.string	"ELEMS"
	.byte	0x8	# priority
	.long	0	# mdextra size

So yes, consumers have to pair prio extracts with their corresponding
operator extract while building the database, by name.  That name will
be mangled, but that should work.


More information about the Algol68 mailing list