|Pliant talk forum
Discussion: Compiler internals
Questions I have about Pliant compiler internals.
|Message posted by maybe Michael FIG on 2006/04/27 04:49:00
|Why does the following code produce "Failed to compile tgt"?
In my investigation, I found that every subexpression of e in the host meta
was already bound to the current module, so that's probably why the substitute failed.
Why is this so? In my former experience with Pliant, the subexpressions
didn't get bound and you had to use "near" often.
# Evaluate a body in the compiler's host with the target module as an
# argument. This allows cross-compiled modules to explicitly
# manipulate the target module.
meta host e
if e:size <> 2
var Str targetIdent := e:0 ident
if targetIdent = ""
var Link:Expression body :> e:1 substitute targetIdent (expression constant "test")
console "tgt: " tgt eol
console "back in the program" eol
|Message posted by hubert.tonneau on 2006/04/27 08:53:49
|All this is implemented in /pliant/language/compiler/expression/expression2.pli
Let's assume that your program manipulates an expression 'e'
e substitute "v1" f1
e substitute "v2" f2
where of course, 'f1' and 'f2' are expressions that you previously computed.
Now, what appends if 'f1' is a complex tree that contains a node with an
indentifier named ... "f2"
With no care, it would be substituted with 'f2' and it would probably be an
unwanted side effect.
So, the binding rule is just protecting agains that:
1. any node of an expression that is an identifier designed to mark a position
for later be substituted with another expression must not be bounded to a
2. any expression that is substituted must have all it's nodes bounded
3. the 'near' method which is often used just before compiling the final
expression is used to bound the remaining unbounded nodes
|Message posted by maybe Michael FIG on 2006/04/27 11:32:14
|Okay, I'm going to need some more help to get this meta going.
console "tgt: " tgt:name eol
console "host: " this_module:name eol
to execute the body in a fresh module (with /pliant/language/compiler.pli loaded,
and tgt defined to be the prior module). Here is my last attempt (which dies
horribly with a reference count violation):
# Rewrite an expression to be completely within a different module.
method e force_near mod
arg_rw Expression e; arg Module mod
e module :> mod
for (var Int i) 0 e:size-1
e:i force_near mod
# Evaluate a body in the compiler's host with the name of the target
# module as an argument. This allows cross-compiled modules to
# explicitly manipulate the target module.
meta host e
if e:size <> 2 or not e:0:is_pure_ident
var Str targetIdent := e:0 ident
if targetIdent = ""
# Put the body into the compiler's module.
var Link:Module mod :> new Module
mod name :> new Str "pliant compiler host module"
mod include the_module:"/pliant/language/compiler.pli" 0
e:1 force_near mod
# Define the expression's target module as a variable in the module.
var Link:GlobalVariable gv :> new GlobalVariable
gv name := targetIdent
gv variable := addressof e:module
gv access := access_read .or. access_write
host_module define targetIdent (addressof gv)
host_module undefine targetIdent (addressof gv)
# We're done.
BTW, I've translated about half of expression.c into Pliant so far. Interesting.
|Message posted by hubert.tonneau on 2006/04/27 11:53:25
|What is 'host_module' ?
PS: Please use double char indentation.
|Message posted by maybe Michael FIG on 2006/04/27 12:15:13
|host_module was a typo... it's actually `mod'.
|Message posted by hubert.tonneau on 2006/04/27 12:52:20
|> var Link:Module mod :> new Module
> mod name :> new Str "pliant compiler host module"
> mod include the_module:"/pliant/language/compiler.pli" 0
You are probably crashing in 'this_module' because it looks for the
external module associated with 'mod' and there is none.
You should very carrefully study the 'load_module'
function in /pliant/language/compiler/module/module.c
as a way to learn the extra details initialised by the standard engine when it
creates a new module.
Also, I'm interested to read an overview of your cross compiler plan.
Some issues are complex so it may save time to exchange about the framework
before too much code is written.
On the other hand, what ever solution you select, translating line by line
the C code to Pliant code is required (except if someone decides to write
a Pliant C syntax parser) at some point, so it's ok to start that part without
|Message posted by maybe Michael FIG on 2006/05/04 04:44:44
|Thanks, the meta is now working the way I want it to.
My next question is about /pliant/language/optimizer/extra.pli, the
optimize_constant_instruction function. I am trying to define a constant
constant access_nocompile 80000000h
Now, technically, I could just define it to be 40000000h, but I would still
like to solve the problem. I get the following error when I run at debug level
The value is too large to fit in an Int
run code generator function optimize_constant /pliant/language/optimizer/extra.pli (internals) 71 1 \
in section pliant optimizer rewrite instructions0
How can I define this constant?
|Message posted by hubert.tonneau on 2006/05/04 09:11:33
|Pliant does arithmetic overflow tests when running at debugging levele 2.
The Pliant parser parses 80000000h as an uInt with value 2^31
Now, when you use this value on some computations, it will be casted to Int,
and on a 32 bits system the final value will be -2^31 so there is an overflow.
Pliant provides operator to prevent overflows to raise error.
As an example:
cast 2^30 Int # no overflow, so no error
cast 2^31 Int # overflow, so error
2^30*2 # the result is uInt so there is no overflow, so no error
(cast 2^30 Int)*2 # overflow, so error
(cast 2^30 Int).*.2 # overflow, but no error
We have introduced '.*.' operator, which is the same as '*' but does not raise
an error in case of overflow
We also have .+. operator
On the other hand, I have not yet defined a special cast operator that would
not raise an overflow.
Basically, it would be implemented as
function no_overflow_cast_int u -> i
arg uInt u ; arg Int i
i := addressof:u map Int
So, without this cast with no overflow operator, the simpler is propably to
define your constant as something like:
constant access_nocompile 80h.*.(cast 2^24 Int)
|Message posted by maybe Michael FIG on 2006/05/05 03:14:50
Though I knew about the .*. operator, I didn't think of using it in the
constant declaration. That seemed to work.