Memory Limit for Visual Studio 2005???

J

Joanna Carter [TeamB]

"Peter Olcott" <[email protected]> a écrit dans le message de [email protected]...

| Yet it does not make this decision on an arbitrary and capricious manner,
it
| only actually pages to disk when it needs to. Since I will most often only
need
| less than 200MB, and the minimum requirements for my application will be
stated
| as 500MB, there is no sense for me to always manually page to disk, when
this
| paging is not necessary.

Don't forget that, if your program is not the only one running on the
machine, then paging may happen sooner than you think, because other
programs may have already exhausted the physical memory before you get a
chance to allocate your memory block.

This is Windows; you are not in charge. And when a user only has 512MB or
even 1GB, then your application isn't going to look too smart; even 2GB can
soon disappear before you get a look in :)

Joanna
 
J

Jon Skeet [C# MVP]

Peter Olcott said:
I have written a couple of compilers, and the jitter is not a compiler.

It converts code from one language (IL) into native code. In what way
is it *not* a compiler?

(I would say that csc is still a compiler though - just because the
target isn't native code doesn't mean it's not compiling, IMO.)
The tricky part is translating the nested do-while and if-then-else
statements comprised of compounds relational expressions into jump
code. The jitter does not need to do this, this part is already done.
All the jitter has to do is to translate pseudo assembly language
into machine code.

That doesn't mean it's not a compiler.
 
P

Peter Olcott

Jon Skeet said:
It converts code from one language (IL) into native code. In what way
is it *not* a compiler?

I already carefully explained in what way it is not a compiler, and you cut that
explanation out. It is not a compiler in that it does not translate nested
compound conditional statements forming if-the-else and do-while control flow
constructs into their equivalent jump code. Although the jitter is commonly
referred to as a compiler its true role is much closer to that of an assembly
language translator.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Peter said:
I already carefully explained in what way it is not a compiler, and you cut that
explanation out. It is not a compiler in that it does not translate nested
compound conditional statements forming if-the-else and do-while control flow
constructs into their equivalent jump code. Although the jitter is commonly
referred to as a compiler its true role is much closer to that of an assembly
language translator.

The difference between a compiler and an assembler is that a compiler
translates from a source language to a target language that are
conceptual different while an assembler translates from a source
language to a target language that are conceptually identical.

Since most of the optimization in a C# program is done by the
JIT compiler and the IL code can be significantly rearranged
then it is obviously not an assembler. It is a compiler.

It is possible to write a language without compound
conditional statements (Fortran 66 as an example does not have
much in this area). And those languages can obviously be compiled.
So you definition of a compiler seems flawed.

And in general it is rather pointless to create ones own
definitions. I could decide to call what everybody else calls
south for north and north for south. But if I ask someone
for directions, then I would get lost quickly. Microsoft
and C# programmers (and for that matter SUN and Java programmers)
call the JIT process for compilation. If you want to communicate
with C# programmers you use the standard terminology or
confusion will arise.

Arne
 
J

Jon Skeet [C# MVP]

Peter Olcott said:
I already carefully explained in what way it is not a compiler, and you cut that
explanation out.

Not really - you said things that many compilers do which the JIT
doesn't have to do. That's not the same way as explaining why it isn't
a compiler.

In a similar way, I could say that a C compiler doesn't have to deal
with closures (which other compilers have to) - that doesn't make the C
compiler any less of a compiler.
It is not a compiler in that it does not translate nested
compound conditional statements forming if-the-else and do-while control flow
constructs into their equivalent jump code.

Could you provide the source for a definition of "compiler" which
requires that?

The wikipedia definition certainly doesn't require it. Here's the
start:

<quote>
A compiler is a computer program (or set of programs) that translates
text written in a computer language (the source language) into another
computer language (the target language). The original sequence is
usually called the source code and the output called object code.
Commonly the output has a form suitable for processing by other
programs (e.g., a linker), but it may be a human readable text file.
</quote>

Which part of that does a JIT compiler not do?
Although the jitter is commonly referred to as a compiler its true
role is much closer to that of an assembly language translator.

In some respects - but not in others.

However, even an assembler counts as a compiler in some senses. The
Wikipedia definition even mentions an assembler as an example:

<quote>
In this manner, assembly languages and the primitive compiler, the
assembler, emerged.
</quote>
 
P

Peter Olcott

Arne Vajhøj said:
The difference between a compiler and an assembler is that a compiler
translates from a source language to a target language that are
conceptual different while an assembler translates from a source
language to a target language that are conceptually identical.

http://en.wikipedia.org/wiki/Compiler
The most common reason for wanting to translate source code is to create an
executable program. The name "compiler" is primarily used for programs that
translate source code from a high level language to a lower level language
(e.g., assembly language or machine language).

If you understand the details of how compilers work and what compilers do you
will realize that the most important thing that compilers do is translating high
level abstractions into lower level implementations.

The most important and difficult one of these tasks is translating from high
level control flow statements into low level control flow statements. Because
the jitter does not do this, calling it a compiler is a stretch. It would be
much more accurate to call it an assembler.

Since it based on an improvement to things such as the Java just in time
compiler calling the .NET feature a just in time compiler is merely an artifact
of the development history rather than an accurate denotation. It would be like
thinking that JavaScript is a script based on Java.
 
P

Peter Olcott

Jon Skeet said:
Not really - you said things that many compilers do which the JIT
doesn't have to do. That's not the same way as explaining why it isn't
a compiler.

In a similar way, I could say that a C compiler doesn't have to deal
with closures (which other compilers have to) - that doesn't make the C
compiler any less of a compiler.


Could you provide the source for a definition of "compiler" which
requires that?

The wikipedia definition certainly doesn't require it. Here's the
start:

<quote>
A compiler is a computer program (or set of programs) that translates
text written in a computer language (the source language) into another
computer language (the target language). The original sequence is
usually called the source code and the output called object code.
Commonly the output has a form suitable for processing by other
programs (e.g., a linker), but it may be a human readable text file.
</quote>

Which part of that does a JIT compiler not do?

Here is a quote for your same source:
http://en.wikipedia.org/wiki/Compiler
The most common reason for wanting to translate source code is to create an
executable program. The name "compiler" is primarily used for programs that
translate source code from a high level language to a lower level language
(e.g., assembly language or machine language).

The JIT "compiler" does not translate high level language control flow
statements to lower level language control flow statements. The most important
part of a compiler' job is translating high level abstractions into lower level
implementations. The most important high level abstraction is high level control
flow statements, and the JIT "compiler" completely skips that part.
 
J

Jon Skeet [C# MVP]

Peter Olcott said:
http://en.wikipedia.org/wiki/Compiler
The most common reason for wanting to translate source code is to create an
executable program. The name "compiler" is primarily used for programs that
translate source code from a high level language to a lower level language
(e.g., assembly language or machine language).

Yup, and IL is a higher level language than native code. Which part of
that definition *isn't* fulfilled by a JIT compiler?
If you understand the details of how compilers work and what compilers do you
will realize that the most important thing that compilers do is translating high
level abstractions into lower level implementations.

You mean high level abstractions like "call this virtual method" into
low level implementations like "look up the actual method in the vtable
and call appropriately"?

It's not as high level as (say) C#, but that doesn't mean it's at the
same level as native code.

Beyond this, you need to read carefully: the quote says that the term
is *primarily* used for programs translating source code from a high
level language. "Primarily" doesn't mean "exclusively".
The most important and difficult one of these tasks is translating from high
level control flow statements into low level control flow statements. Because
the jitter does not do this, calling it a compiler is a stretch. It would be
much more accurate to call it an assembler.

And as Wikipedia states, an assembler is a primitive compiler. I would
say a JIT is significantly more than an assembler though.

Note that the JIT *does* need to deal with some higher level control
flow statements than the JIT understands - "switch" is a good example
of this.
Since it based on an improvement to things such as the Java just in time
compiler calling the .NET feature a just in time compiler is merely an artifact
of the development history rather than an accurate denotation.

That "since" doesn't make logical sense. Just because Java had a JIT
compiler before .NET existed doesn't make the word "compiler"
inappropriate.
It would be like thinking that JavaScript is a script based on Java.

Not at all. That just shows that things *can* be badly named - it is
not evidence that the JIT compiler *is* badly named.
 
J

Jon Skeet [C# MVP]

Peter Olcott said:
Here is a quote for your same source:
http://en.wikipedia.org/wiki/Compiler
The most common reason for wanting to translate source code is to create an
executable program. The name "compiler" is primarily used for programs that
translate source code from a high level language to a lower level language
(e.g., assembly language or machine language).

Dealt with in another post.
The JIT "compiler" does not translate high level language control flow
statements to lower level language control flow statements.

Care to enlighten me as to where in x86 the "switch" statement is
defined? How about virtual method calls?
The most important part of a compiler' job is translating high level
abstractions into lower level implementations.

As I said in another post, the JIT does plenty of this.
The most important high level abstraction is high level control
flow statements, and the JIT "compiler" completely skips that part.

So your definition of "compiler" completely excludes anything which
converts one language into another if the source language doesn't have
any higher level control flow statements. It's an interesting
definition of a compiler, but not one which you've shown that anyone
else uses.

On the other hand, I *have* produced a definition of "compiler" which
the JIT compiler certainly meets, and which is clearly used by others.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Peter said:
http://en.wikipedia.org/wiki/Compiler
The most common reason for wanting to translate source code is to create an
executable program. The name "compiler" is primarily used for programs that
translate source code from a high level language to a lower level language
(e.g., assembly language or machine language).

If you understand the details of how compilers work and what compilers do you
will realize that the most important thing that compilers do is translating high
level abstractions into lower level implementations.

Yes.

IL is at a higher level than the x86 instruction set.
The most important and difficult one of these tasks is translating from high
level control flow statements into low level control flow statements. Because
the jitter does not do this, calling it a compiler is a stretch. It would be
much more accurate to call it an assembler.

I thougth the processs of compiling high level compound statements
to assembler/machinecode was something any CS student learned. While
writing a good optimizing compiler was an art.

Do you consider what we call a Fortran 66 compiler for a
Fortran 66 assembler because it does not have block if
statements ?

It does not make much sense to me to define compilers by
requiring the source language to have certain high level
control flow statements.
Since it based on an improvement to things such as the Java just in time
compiler calling the .NET feature a just in time compiler is merely an artifact
of the development history rather than an accurate denotation.

Language is an artifact of history.
It would be like
thinking that JavaScript is a script based on Java.

This is actually a very good example. But not quite as you think it is.

If you use the term "JavaScript" then everybody knows what you
are talking about.

If you use the term "LiveScript" or "ECMAScript", then much
fewer people understand you.

NetScape gave it the name JavaScript many years ago. It has
been general accepted.

Arne
 
P

Peter Olcott

Jon Skeet said:
Yup, and IL is a higher level language than native code. Which part of
that definition *isn't* fulfilled by a JIT compiler?


You mean high level abstractions like "call this virtual method" into
low level implementations like "look up the actual method in the vtable
and call appropriately"?

It's not as high level as (say) C#, but that doesn't mean it's at the
same level as native code.

Beyond this, you need to read carefully: the quote says that the term
is *primarily* used for programs translating source code from a high
level language. "Primarily" doesn't mean "exclusively".


And as Wikipedia states, an assembler is a primitive compiler. I would
say a JIT is significantly more than an assembler though.

And significantly less than a compiler, closer to an assembler than a compiler.
Note that the JIT *does* need to deal with some higher level control
flow statements than the JIT understands - "switch" is a good example
of this.

This can be translated into a jump table quite easily. It does not require
anything close to the level of difficulty of translating nested compound
conditional control flow statements into their equivalent jump code.
 
P

Peter Olcott

Jon Skeet said:
Dealt with in another post.


Care to enlighten me as to where in x86 the "switch" statement is
defined? How about virtual method calls?

A similar construct could be created in the typical assembly language using very
powerful macro substitution.
As I said in another post, the JIT does plenty of this.

Not enough to be accurately construed as a compiler. It would probably be a
little less than halfway between the typical high level language compiler and
the typical assembler. This would make it a very high level assembler.

Even languages that lack high level control flow constructs typically translate
high level mathematical constructs into the sequence of low level steps required
by a pseudo (or actual) machine language. From what I recall, this is another
compiler feature that the jitter is missing.
 
P

Peter Olcott

Arne Vajhøj said:
Yes.

IL is at a higher level than the x86 instruction set.
Yes.


I thougth the processs of compiling high level compound statements
to assembler/machinecode was something any CS student learned. While
writing a good optimizing compiler was an art.

Do you consider what we call a Fortran 66 compiler for a
Fortran 66 assembler because it does not have block if
statements ?

It still would translate high level mathematical expressions into their
equivalent low level sequence of operations, so it would still be a compiler. If
a source language lacks both of the two key high level abstractions typically
associated with 3GL languages (high level control flow, and high level
expression processing) Then the "high level" language is not high enough to
accurately call it a 3GL.

One of my inventions that I never completed because it would not likely be
patentable, and because its potential market kept shrinking was a language that
I called 2point5GL. This language embedded the {if-then-else, do-while, and
while} control flow constructs from the "C" programming language into any
assembly language.

As you can tell from its name, it was not high enough to call it a 3GL (high
level language), neither was it low enough to call it a 2GL, (assembly level
language).
It does not make much sense to me to define compilers by
requiring the source language to have certain high level
control flow statements.

You have to have some way to delineate it otherwise every assembler would be a
compiler and common usage conventions clearly distinguish between compilers and
assemblers. The jitter is a very high level assembler.
 
J

Jon Skeet [C# MVP]

Peter Olcott said:
And significantly less than a compiler, closer to an assembler than a compiler.

That makes no sense given the definition of compiler includes assembler
(according to the quote).
This can be translated into a jump table quite easily. It does not require
anything close to the level of difficulty of translating nested compound
conditional control flow statements into their equivalent jump code.

Be that as it may, it's still a higher level control flow in IL than in
native code. Why should the difficulty level decide whether or not
something should be called a compiler?
 
J

Jon Skeet [C# MVP]

Peter Olcott said:
You have to have some way to delineate it otherwise every assembler would be a
compiler and common usage conventions clearly distinguish between compilers and
assemblers. The jitter is a very high level assembler.

I find it amusing that *now* you're appealing to "common usage
conventions" despite the fact that in common usage the JIT clearly *is*
regarded as a compiler, and your arbitrary delineation based on control
flow is anything but common.
 
L

Lucian Wischik

Peter Olcott said:
The most important and difficult one of these tasks is translating from high
level control flow statements into low level control flow statements.

No way, not at all. That one's a trivial transformation. Harder parts
are type inference and analysis, name/type resolution and binding,
single assignment translation and register colouring.
 
P

Peter Olcott

Lucian Wischik said:
No way, not at all. That one's a trivial transformation. Harder parts
are type inference and analysis, name/type resolution and binding,
single assignment translation and register colouring.

Great can I hire you for a trivial amount of money to build a Yacc based parser
that recognizes the basic "C" control flow constructs of {if-then-else, while,
and do-while} and produces simple bytecode based jump code that can be used by
an interpreter?

This interpreter will not even have to process arithmetic expressions, it only
needs to process the case that you labeled as trivial. This includes arbitrarily
nested conditional statements and arbitrarily complex compound conditional
expressions. Each element of the compound conditional expression only needs to
 
L

Lucian Wischik

Peter Olcott said:
Great can I hire you for a trivial amount of money to build a Yacc based parser
that recognizes the basic "C" control flow constructs of {if-then-else, while,
and do-while} and produces simple bytecode based jump code that can be used by
an interpreter?

Here, I had 30 minutes free after our christmas turkey so you can have
it for free. Being a 30 minute free piece of code it doesn't have
comments or error-checking. I'm assuming that yacc has already turned
the input language into an AST. I use "hcode" for the high-level AST
which has the control-flow constructs you wanted, and "mc" for the
bytecode based jump code. I wrote it in F#, a functional .net
language, since it seemed most appropriate and you can easily interop
from C#.

type hcode = SEQUENCE of hcode*hcode
| IF of string*hcode*hcode
| WHILE of string*hcode
| DOWHILE of hcode*string
| ATOM of string

type mc = MATOM of string
| MCOMP of string
| MIFFALSEJUMP of string
| MIFTRUEJUMP of string
| MJUMP of string


let fcount = ref 0
let freshstring = fun (s:string) -> let r = !fcount in fcount:=r+1;
s^"_"^r.ToString()

let compile : hcode -> mc array = fun code ->
let gend : (string list * mc * string list) array ref = ref [| |] //
the generated code
let append = fun (labstart,mcode,labend) -> gend := Array.append
!gend [|(labstart,mcode,labend)|]
let rec subcompile = fun (labstart,code,labend) ->
match code with
| ATOM(atom) -> append(labstart,MATOM(atom),labend)
| SEQUENCE(c1,c2) -> subcompile(labstart,c1,[]);
subcompile([],c2,labend)
| IF(test,cif,celse) ->
let elsebranch,after =
freshstring("else_"^test),freshstring("endif_"^test)
append(labstart,MCOMP(test),[]);
append([],MIFFALSEJUMP(elsebranch),[]);
subcompile([],cif,[]);
append([],MJUMP(after),[]);
subcompile([elsebranch],celse,after::labend)
| WHILE(test,body) ->
let start,after = freshstring("while_"^test),
freshstring("endwhile_"^test)
append(start::labstart,MCOMP(test),[]);
append([],MIFFALSEJUMP(after),[]);
subcompile([],body,[]);
append([],MJUMP(start),after::labend)
| DOWHILE(body,test) ->
let start = freshstring("do_"^test)
subcompile(labstart,body,[]);
append([],MCOMP(test),[]);
append([],MIFTRUEJUMP(start),labend)
let progstart,progend = freshstring("mainstart"),
freshstring("mainend")
subcompile([progstart],code,[progend])
// now put strings into a map
let labs:(Map<string,int>) ref = ref (Map.Empty())
for i = 0 to Array.length(!gend)-1 do
let (labstart,code,labend) = (!gend).(i)
let _ = List.map (fun s -> labs := (!labs).Add(s,i)) labstart
let _ = List.map (fun s -> labs := (!labs).Add(s,i+1)) labend
()
done
let al = !labs
// now resolve the names
let resolve = fun (labstart,mcode,labend) ->
match mcode with
| MATOM(s) -> MATOM(s)
| MCOMP(s) -> MCOMP(s)
| MIFFALSEJUMP(s) -> MIFFALSEJUMP((!labs)..ToString())
| MIFTRUEJUMP(s) -> MIFTRUEJUMP((!labs)..ToString())
| MJUMP(s) -> MJUMP((!labs)..ToString())
// and that's it!
Array.map resolve (!gend)


Degenerate test case: if you give it the input AST
IF("conda",ATOM "atom1", SEQUENCE(ATOM "atom2", ATOM "atom3"))
then it gives as output
0: CMP conda
1: IFFALSEJUMP 4
2: atom1
3: JUMP 6
4: atom2
5: atom3


PS. thanks for your kind offer to hire me, but I only just joined the
VB compiler team recently and it wouldn't be appropriate for me to
moonlight!
 
P

Peter Olcott

Lucian Wischik said:
Here, I had 30 minutes free after our christmas turkey so you can have
it for free. Being a 30 minute free piece of code it doesn't have
comments or error-checking. I'm assuming that yacc has already turned
the input language into an AST. I use "hcode" for the high-level AST
which has the control-flow constructs you wanted, and "mc" for the
bytecode based jump code. I wrote it in F#, a functional .net
language, since it seemed most appropriate and you can easily interop
from C#.

I was flabbergasted by the degree of productivity that your seem to have
demonstrated here. Could you point me in the direction where I can learn this
degree of productivity in compiler construction? I want to be able to do
something comparable to what you have done, and preferably in a native code
language such as C++.
type hcode = SEQUENCE of hcode*hcode
| IF of string*hcode*hcode
| WHILE of string*hcode
| DOWHILE of hcode*string
| ATOM of string

type mc = MATOM of string
| MCOMP of string
| MIFFALSEJUMP of string
| MIFTRUEJUMP of string
| MJUMP of string


let fcount = ref 0
let freshstring = fun (s:string) -> let r = !fcount in fcount:=r+1;
s^"_"^r.ToString()

let compile : hcode -> mc array = fun code ->
let gend : (string list * mc * string list) array ref = ref [| |] //
the generated code
let append = fun (labstart,mcode,labend) -> gend := Array.append
!gend [|(labstart,mcode,labend)|]
let rec subcompile = fun (labstart,code,labend) ->
match code with
| ATOM(atom) -> append(labstart,MATOM(atom),labend)
| SEQUENCE(c1,c2) -> subcompile(labstart,c1,[]);
subcompile([],c2,labend)
| IF(test,cif,celse) ->
let elsebranch,after =
freshstring("else_"^test),freshstring("endif_"^test)
append(labstart,MCOMP(test),[]);
append([],MIFFALSEJUMP(elsebranch),[]);
subcompile([],cif,[]);
append([],MJUMP(after),[]);
subcompile([elsebranch],celse,after::labend)
| WHILE(test,body) ->
let start,after = freshstring("while_"^test),
freshstring("endwhile_"^test)
append(start::labstart,MCOMP(test),[]);
append([],MIFFALSEJUMP(after),[]);
subcompile([],body,[]);
append([],MJUMP(start),after::labend)
| DOWHILE(body,test) ->
let start = freshstring("do_"^test)
subcompile(labstart,body,[]);
append([],MCOMP(test),[]);
append([],MIFTRUEJUMP(start),labend)
let progstart,progend = freshstring("mainstart"),
freshstring("mainend")
subcompile([progstart],code,[progend])
// now put strings into a map
let labs:(Map<string,int>) ref = ref (Map.Empty())
for i = 0 to Array.length(!gend)-1 do
let (labstart,code,labend) = (!gend).(i)
let _ = List.map (fun s -> labs := (!labs).Add(s,i)) labstart
let _ = List.map (fun s -> labs := (!labs).Add(s,i+1)) labend
()
done
let al = !labs
// now resolve the names
let resolve = fun (labstart,mcode,labend) ->
match mcode with
| MATOM(s) -> MATOM(s)
| MCOMP(s) -> MCOMP(s)
| MIFFALSEJUMP(s) -> MIFFALSEJUMP((!labs)..ToString())
| MIFTRUEJUMP(s) -> MIFTRUEJUMP((!labs)..ToString())
| MJUMP(s) -> MJUMP((!labs)..ToString())
// and that's it!
Array.map resolve (!gend)


Degenerate test case: if you give it the input AST
IF("conda",ATOM "atom1", SEQUENCE(ATOM "atom2", ATOM "atom3"))
then it gives as output
0: CMP conda
1: IFFALSEJUMP 4
2: atom1
3: JUMP 6
4: atom2
5: atom3


PS. thanks for your kind offer to hire me, but I only just joined the
VB compiler team recently and it wouldn't be appropriate for me to
moonlight!
 
P

Peter Olcott

I see now that the key to greatly enhanced productivity in compiler construction
is the
AST (Abstract Syntax Tree). Yacc could build these relatively easily. Once build
code generation becomes much simpler.

Lucian Wischik said:
Peter Olcott said:
Great can I hire you for a trivial amount of money to build a Yacc based
parser
that recognizes the basic "C" control flow constructs of {if-then-else, while,
and do-while} and produces simple bytecode based jump code that can be used by
an interpreter?

Here, I had 30 minutes free after our christmas turkey so you can have
it for free. Being a 30 minute free piece of code it doesn't have
comments or error-checking. I'm assuming that yacc has already turned
the input language into an AST. I use "hcode" for the high-level AST
which has the control-flow constructs you wanted, and "mc" for the
bytecode based jump code. I wrote it in F#, a functional .net
language, since it seemed most appropriate and you can easily interop
from C#.

type hcode = SEQUENCE of hcode*hcode
| IF of string*hcode*hcode
| WHILE of string*hcode
| DOWHILE of hcode*string
| ATOM of string

type mc = MATOM of string
| MCOMP of string
| MIFFALSEJUMP of string
| MIFTRUEJUMP of string
| MJUMP of string


let fcount = ref 0
let freshstring = fun (s:string) -> let r = !fcount in fcount:=r+1;
s^"_"^r.ToString()

let compile : hcode -> mc array = fun code ->
let gend : (string list * mc * string list) array ref = ref [| |] //
the generated code
let append = fun (labstart,mcode,labend) -> gend := Array.append
!gend [|(labstart,mcode,labend)|]
let rec subcompile = fun (labstart,code,labend) ->
match code with
| ATOM(atom) -> append(labstart,MATOM(atom),labend)
| SEQUENCE(c1,c2) -> subcompile(labstart,c1,[]);
subcompile([],c2,labend)
| IF(test,cif,celse) ->
let elsebranch,after =
freshstring("else_"^test),freshstring("endif_"^test)
append(labstart,MCOMP(test),[]);
append([],MIFFALSEJUMP(elsebranch),[]);
subcompile([],cif,[]);
append([],MJUMP(after),[]);
subcompile([elsebranch],celse,after::labend)
| WHILE(test,body) ->
let start,after = freshstring("while_"^test),
freshstring("endwhile_"^test)
append(start::labstart,MCOMP(test),[]);
append([],MIFFALSEJUMP(after),[]);
subcompile([],body,[]);
append([],MJUMP(start),after::labend)
| DOWHILE(body,test) ->
let start = freshstring("do_"^test)
subcompile(labstart,body,[]);
append([],MCOMP(test),[]);
append([],MIFTRUEJUMP(start),labend)
let progstart,progend = freshstring("mainstart"),
freshstring("mainend")
subcompile([progstart],code,[progend])
// now put strings into a map
let labs:(Map<string,int>) ref = ref (Map.Empty())
for i = 0 to Array.length(!gend)-1 do
let (labstart,code,labend) = (!gend).(i)
let _ = List.map (fun s -> labs := (!labs).Add(s,i)) labstart
let _ = List.map (fun s -> labs := (!labs).Add(s,i+1)) labend
()
done
let al = !labs
// now resolve the names
let resolve = fun (labstart,mcode,labend) ->
match mcode with
| MATOM(s) -> MATOM(s)
| MCOMP(s) -> MCOMP(s)
| MIFFALSEJUMP(s) -> MIFFALSEJUMP((!labs)..ToString())
| MIFTRUEJUMP(s) -> MIFTRUEJUMP((!labs)..ToString())
| MJUMP(s) -> MJUMP((!labs)..ToString())
// and that's it!
Array.map resolve (!gend)


Degenerate test case: if you give it the input AST
IF("conda",ATOM "atom1", SEQUENCE(ATOM "atom2", ATOM "atom3"))
then it gives as output
0: CMP conda
1: IFFALSEJUMP 4
2: atom1
3: JUMP 6
4: atom2
5: atom3


PS. thanks for your kind offer to hire me, but I only just joined the
VB compiler team recently and it wouldn't be appropriate for me to
moonlight!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top