Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!rutgers!cs.utexas.edu!sun-barr!decwrl!megatest!djones From: djones@megatest.UUCP (Dave Jones) Newsgroups: comp.lang.c Subject: Re: Translating Pascal ==> C: nested procedures Message-ID: <5529@goofy.megatest.UUCP> Date: 5 Jun 89 22:37:43 GMT References: <17880@mimsy.UUCP> Organization: Megatest Corporation, San Jose, Ca Lines: 117 > In article <3276@cps3xx.UUCP> rang@cpsin3.cps.msu.edu (Anton Rang) writes: >>... I've heard of several "Pascal to C" translators. How do they handle >>nested procedures? > I've never seen one of these Pascal to C translators, but I can offer a suggestion as to how to go about it. In fact, it's the only reasonable way to do it that I can think of right off, without doing some pretty fancy calculating in the compiler ( -- Oops. "Translator"). For a procedure whose locals are referenced by a nested procedure, rather than passing single parameters to it, pass a reference to a struct which contains all the parameters. Likewise, declare all its locals in a struct. Maintain two "display-pointers" for each lexical level, one pointing to the current parameters at that level, one to the current locals at that level. (If after finishing this article, you wonder why two pointers are needed for each level, rather than just one pointing to record containing both parameters and locals, think about the the "forward" directive and a "one pass" compiler.) The C code won't be very readable to us mere humans, but if you keep the Pascal source, and only use the C as an intermediate, that's okay. If you want to convert to C as source, well... I never liked nested scope anyway. Use the generated C as a hint to convert the routines so that they pass pointers to structures, rather than using scope. Example... program foo(input, output); var global: integer; procedure one(var x: integer; y: integer); var z: integer; procedrue two; begin global := 5; x := 3; z := 4; end; begin x := 2; two; end; begin global := 1; one(global, global); end; There follows a C equivalent. (Hope I don't mess this up. I just winged it to give you the idea. I also omited initialization code for the files input and output, etc. ) Some of the code which handles the display could be optimized out, but we want it here for instruction. #define MAX_LEVEL 16 /* or whatever */ struct { void* params; void* locals; } _display[MAX_LEVEL]; main(argc, argv) char** argv; { /* _init(argc, argv); */ foo(); } /* Structure definitions for parameter and local * variable "activations". */ typedef struct { int global; } Var_struct_foo; typedef struct { int *x; int y } Parm_struct_one; typedef struct { int z; } Var_struct_one; foo_one_two() { ((Var_struct_foo*)(_display[1].locals))->global = 5; *(((Parm_struct_one*)(_display[2].params))->x) = 3; ((Var_struct_one*)(_display[2].locals))->z = 4; } foo_one(params) register Parm_struct_one *params; { void* save_params = _display[2].params; void* save_locals = _display[2].locals; Var_struct_one Var_one; _display[2].locals = (void*)(&Var_one); _display[2].params = (void*)(params); *(params->x) = 2; foo_one_two(); end: _display[2].locals = save_locals; _display[2].params = save_params; } foo() { Var_struct_foo Var_foo; _display[1].locals = (void*) &Var_foo; Var_foo.global = 1; { Parm_struct_one Parm_one; Parm_one.x = &Var_foo.global; Parm_one.y = Var_foo.global; foo_one(&Parm_one); } }