Language

Translating from C to Pliant

Pliant programming language is a superset of C, so that you can translate a C program to Pliant, mostly line by line.

Parenthesing and blocs

When calling a function, Pliant puts the function name inside parenthesis.
Then C uses coma for arguments separation, whereas Pliant just uses space.
Let's assume that 'fb' is a function with two numeric arguments:

C

Pliant

fb(12,20);

fb 12 20
or
(fb 12 20)

C

Pliant

fa(5)

fa 5

fa:5
or
fa:5

In Pliant colon is just a way to replace parenthesis when there is only one argument.

Pliant

same as

a:b
a:b:c:d

(a b)
(((a b) c) d)

Pliant uses indentation for blocs, just like Python, whereas C uses { }
Then, in C each instruction ends with a semicolon whereas in Pliant semicolon is only used as a separator when several instructions are provided on the same line.

C

Pliant

<instruction1> ;
<instruction2> ;

<instruction1> ; <instruction2> ;

if <condition> {
  <do_something>
}

<instruction1>
<instruction2>

<instruction1> ; <instruction2>

if <condition>
  <do_something>

In Pliant, the standard indentation is two spaces.

Also, it is still possible to use { } in Pliant for one line compact blocs :

C

Pliant

if <condition> { <instr1> ; <instr2> ; <instr3> ; }

if <condition> { <instr1> ; <instr2> ; <instr3> }

Pliant comment is starting with hastag character and ending at the end of the line :

C

Pliant

fa(5); // a comment

fa 5 # a comment

Numerical types and local variables

C

Pliant

uint8_t
uInt16_t
uInt32_t
uInt64_t
uint128_t
int8_t
int16_t
int32_t
int64_t
int128_t

uInt8
uInt16
uInt32
uInt64
uInt128
Int8
Int16
Int32
Int64
Int128

As you can see in the following table, C should be 64 bits on 64 bits plateforms, but it's not. This makes C a crap language :

Plateform

C pointer size

C int size

C long size

C size_t size

Pliant Int size

32 bits
Unix 32 bits
Windows 64 bits

32 bits
64 bits
64 bits

32 bits
32 bits
32 bits

32 bits
64 bits
32 bits

32 bits
64 bits
64 bits

32 bits
64 bits
64 bits

So, we have potential trouble when translating C 'int' and 'unsigned int' to Pliant.
When they are used to store an arbitrary size number, they should be translated as 'Int' and 'uInt', but sometime, they might truely mean 'int32_t' and 'uint32_t' so be translated to 'Int32' and 'uInt32'.

Then, C 'long' and 'unsigned long' should also be translated to Pliant 'Int' and 'uInt', but in very rare cases for code intended only for Windows 64 bits, they might also mean 'int32_t' or 'uint32_t' so must be translated to 'Int32' and 'uInt32'

C type

Should mean in the program

But might mean

Sould be translated as Pliant

int
long
size_t

32 bits is ok, but 64 bits is also
32 bits on 32 bits plateforms, 64 bits on 64 bits plateforms

strictly 32 bits
32 bits under Windows 64 bits

Int
Int
uInt

When defining structure data types, it is even more difficult to select if C 'int' must be translated as Pliant 'Int' or as 'Int32'.

Here is the summary of types translation from clean C code to Pliant :

C

Pliant

unsigned char

uInt8

char

Int8

unsigned short

uInt16

short

Int16

unsigned int

most time uInt, but simetime uInt32

int

most time Int, but sometime Int32

unsigned long

uInt, absolutely valid only under Unix

long

Int, absolutely valid only under Unix

unsigned long long

uInt64

long long

Int64

size_t

uInt

Pliant uses 'var' instruction to declare local variables. All local variables must be declared before use.
Pliant uses 'gvar' to delcare global variables.
If you need to declare several local variables and provide initial values, then with Pliant you need one instruction per local variable :

C

Pliant

long a, b, c;

long a=0, b=12, c=15;

var Int a b c

var Int a := 0 ; var Int b := 12 ; var Int c := 15

Pliant casting is using 'cast' instruction:

C

Pliant

Comment

unsigned long a; long b; unsigned long c;
c = b;
c = a * (unsigned long)b;

var uInt a ; var Int b ; var uInt c
c := cast b uInt
c := a * (cast b uInt)



Forces to compute unsigned multiplication.

Arithmetic

C affectation is equal sign whereas Pliant affectation is colon followed by equal.

C

Pliant

long a, b, c;
c = a + b;
c = a-b;
c = a*b;
c := a/b;
c = a%b;
c := a << b;
c = a >> b;
c = a & b;
c := a | b;
c = a ^ b;
c = ~ a;

var Int a b c
c := a+b
c := a-b
c := a*b
c := a\b
c := a % b
c := a * 2^b
c := a \ 2^b
c := a .and. b
c := a .or. b
c := a .xor. b
c := .not. a

In Pliant backslash is integer division and slash is floatting point division.

Here are Pliant equivalents of some C combined operators, assuming that 'fa' is a function using a single numerical argument :

C

Pliant

long a, b;
a += b;
a -= b;
a *= b;
a /= b;
b = f(a++);
b = f (++a);
b = f(a--);
b = fa(--a)

var Int a b
a += b
a -= b
a *= b
a \= b
b := f a ; a += 1
a += 1 ; b := f a
b := fa a ; a -= 1
a -= 1 ; b := f a

Comparisons and booleans

C equality comparison is double equal whereas Pliant equality comparison is equal sign.

C

Pliant

long a, b;
a == b
a < b
a <= b
a > b
a >= b
a != b

var Int a b
a = b
a < b
a <= b
a > b
a >= b
a <> b

In C, a boolean is just an integer, and it is assumed to be true if it's value is non zero.
In Pliant, a boolean has type 'CBool' and is semantically not a numeric value.

C

Pliant

int a, b;
a && b
a || b
! a
1
0

var CBool a b
a and b
a or b
not a
true
false

It is not recommanded, but if you truely need to handle a Pliant boolean as a numerical value where true means non zero, you can :

C

Pliant

Comment

int c, i;
i = c;
i = c;
i = c;
c = i;
c = i;
c = i;

var CBool c ; var Int i
i := c
i := shunt c 1 0
i := addressof:c map Int
c := i
c := i<>0
addressof:c map Int := i


Forbidden in Pliant, a boolean is not a numerical value.
Allowed in Pliant, but not strictly equivalent of the C code because C 'c' might not be zero or one.
Allowed in Pliant.
Forbidden in Pliant, a boolean is not a numerical value.
Allowed in Pliant, but not strictly equivalent of the C code because C 'i' might not be zero or one.
Also allowed in Pliant.

Controls

C

Pliant

if <condition> {
  <do_something>
} else {
  <do_another_thing>
}

while <condition> {
  <do_something>
}

int i, s;
for (int i=0; i<s; i++) {
  <do_something> }

 



for (int i=6; i<=12; i += 2) {
  <do_something> }

do {
  <do_something>
} while <condition>;

if <condition>
  <do_something>
else
  <do_another_thing>

while <condition>
  <do something>

var Int s
for (var Int i) 0 s-1
  <do_something>

or

var Int i s
for i 0 s-1
  <do_something>

for (var Int i) 6 12 step 2
  <do_something>

part do_while
  <do_something>
  if <condition>
    restart do_while

Pliant has no direct equivalent to C 'goto', 'continue' and 'break' instructions.
On the other hand, a Pliant program can define 'part' blocs identified by a name, then within the bloc, use 'leave' instruction to jump at the end of the bloc, or 'restart' instruction to jump at the beginning of it. This can be used to emulate C 'continue' and 'break' instructions, and most of C 'goto' use cases.

C

Pliant

int j = 50;
for (int  i= 0; i < 10; i++) {
  if (i == 2)
    continue;
  j += i;

var Int j := 50
for (var Int i) 0 9
  part the_lap
    if i=2
      leave the_lap  
  j += i

int j = 50;
for (int i=0; i < 10; i++) {
  if (i == 7)
    break;
  j += i;

var Int j := 50
part the_loop
  for (var Int i) 0 9
    if i = 7
      leave the_loop
    j += i

Pliant equivalent to C question mark then colon is 'shunt':

C

Pliant

<condition1> ? <value1> : <condition2> ? <value2> : <value3>

shunt <condition1> <value1> <condition2> <value2> <value3>

Declaring structures

Pliant uses 'type' and 'field' to declare structures :

C

Pliant

typedef struct
{
  void *a;
  long s;
} Foo;

type Foo
  field Address a
  field Int s

C compilers tend to add implicit padding to align fields according to their size, whereas with Pliant, padding must be explicit. Here is an example :

C

Pliant

typedef struct
{
  int8_t a;
  int32_t b;
} Bar;

type Bar
  field Int8 a
  field (Array Int8 3) padding
  field Int32 b

Declaring a function

Pliant uses 'arg', 'arg_rw', 'arg_w' instructions in the function body to specify arguments types and minus followed by greater than sign to specify the name of the optional result, whereas modern C provides arguments types in the function header, provides no name for the result, and specifies void type for the result if the function has no result.
For the result, Pliant can also use 'arg_R', 'arg_RW' and 'arg_C'. They mean that the address of the result will be returned. 'arg_R' means that the content of the result should not be modified by the caller, as opposed to 'arg_RW'. Then 'arg_C' means that if the caller has only read access to the first argument, it shoud not modify the result, but if it has read write access to the first argument, then it is allowed to modify the result. The 'C' of 'arg_C' stands for consistent.

C

Pliant

Alternative, since Pliant provides a name for the result

long fact(long x)
{
  if (x == 0)
    return 1;
  else
    return x * fact(x-1);
}

function fact x -> y
  arg Int x y
  if x = 0
    return 1
  else
    return x * (fact x-1)

function fact x -> y
  arg Int x y
  if x = 0
    y := 1
  else
    y := x * (fact x-1)

In Pliant 'arg' means that the argument will be only read, 'arg_rw' means that it will be modified by the called function.
Then 'arg_w' is a special case of 'arg_rw' specifying that the value of the argument at the end of the function does not depend on it's value at the beginning, that is that the argument will be completely written, not just updated.

Pliant passes an argument by value only if it's atomic, and futhermore it is either read only or it is the result.
Pliant atomic data types are mostly 'uInt', 'Int', 'Address', 'Pointer:xxx' where 'xxx' is any Pliant type. More precisely, Pliant atomic data types are the data types that have the same size as Pliant 'Int', and futher more do not have initialisation, copy or destruction special routines.

In order to illustrate all these rules, here are various arguments translation form C to Pliant, assuming 'Foo' is the structure type we previously declared:

C argument

Pliant argument

Why ?

long a
long *a
constant Foo *a
Foo *a
Foo a

arg Int a
arg_rw Int a
arg Foo a
arg_rw Foo a
Not possible with Pliant

A read only atomic argument, passed by value.
A read write atomic argument, passed by address.
A read only non atomic argument, passed by address.
A read write argument, passed by address.
Because Pliant always passes non atomic arguments by address.

C 'void *' is the equivalent of Pliant 'Address' data type, and Pliant 'Address' data type is atomic, so according to the previously specifyed rules, in a function prototype, C 'void *' and 'void **' will be translated according to the following table :

C argument

Pliant argument

Why ?

void *a
const void *
void **a

arg Address a
arg Address a
arg_rw Address a

Pliant 'arg' means that the function will not change the passed memory address, but it may well change the memory area it points.
Pliant cannot specfiy that the pointed memory area will not be modified, but the translation is ok.
Pliant 'arg_rw' means that the function might change the pointer, not only the memory it points.

Here is another example of a function prototype translation :

C

Pliant

void my_function(const Foo *a, int b, void *c, long *r)
{
  ...
}

function my_function a b c r
  arg Foo a ; arg Int b ; arg Address c ; arg_rw Int r
  ...

Lastly, a Pliant argument declared with 'arg', as opposed to 'arg_rw', is read only also inside the function, as opposed C :

C

Invalid Pliant code

Valid Pliant code

void some_function(long a,long *b)
{
  while (a > 0) {
     *b := *b + a;
     a -= 3;

  }
}

function some_function a b
  arg Int a ; arg_rw Int b
  while a > 0
     b := b + a
     a -= 3 # Modifying 'a' is not allowed

function some_function a b
  arg Int a ; arg_rw Int b
  var Int wa := a
  while wa >= 0
     b := b + wa
     aw -= 3

Pointers

Pliant pointers are automatically dereferenced.
In Pliant, colon followed by greater than sign means set the pointer and colon followed by equal sign means set the pointed value:

C

Pliant

long *a, *b, c;
a = &c ;
b = a;
*b = *a ;
c = *a;
b = a + 3;
c = a[5];

var Pointer:Int a b ; var Int c
a :> c
b :> a
b := a
c := a
b :> addressof:a map Int 3
c := addressof:a map Int 5

If 'fb' is a function with two numerical arguments, you have to write :
fb (addressof:c map Int) 5
and not just:
fb addressof:a map Int 5
because without parenthesis, 'fb' would be assumed to have four arguments.

Now the double pointers :

C

Pliant

long **a, **b, *p, c;
a = &p ;
b = a;
*b = *a ;
**b = **a;

var (Pointer Pointer:Int) a b ; var Pointer:Int p ; var Int c
a :>> p
b :>> a
b :> a
b := a

Pliant has a special type 'Address' for storing a memory address, whereas C code tend to use 'void *':

C

Pliant

Comment

void *a, *t; long *p, v;
a = (void *)&v;
p = (long *)a;
*p = *(long *)a;
*p = ((long *)a)[5];
*p = *((long *)a+5)
t = (void *)((int *)a+3);
a = NULL;
a = 0;
p = null;
if (a == NULL) {
  ...
}
if (p == NULL) {
  ...
}

var Address a t ; var Pointer:Int p ; var Int v
a := addressof v
p :> a map Int
p := a map Int
p := a map Int 5
p := (a translate Int 5) map Int
t := a translate Int 3
a := null
a := cast 0 Address
p :> null map Int
if a=null
  ...

if addressof:p = null
  ...
or
if not exists:p
  ...






Same as previous, both in C and Pliant.


Pliant requires explicit casting for turning an integer to an address or a pointer.