1MODULE OPC; (* copyright (c) J. Templ 12.7.95 / 3.7.96 *) 2(* C source code generator version 3 4 30.4.2000 jt, synchronized with BlackBox version, in particular 5 various promotion rules changed (long) => (LONGINT), xxxL avoided 6*) 7 8 IMPORT OPT, OPM, Configuration, SYSTEM; 9 10 CONST demoVersion = FALSE; 11 12 13 CONST 14 UndefinedType = 0; (* named type not yet defined *) 15 ProcessingType = 1; (* pointer type is being processed *) 16 PredefinedType = 2; (* for all predefined types *) 17 18 DefinedInHdr = 3+OPM.HeaderFile; (* named type has been defined in header file *) 19 DefinedInBdy = 3+OPM.BodyFile; (* named type has been defined in body file *) 20 21 BasicIncludeFile = "SYSTEM"; 22 23 Export = "export "; (* particularily introduced for VC++ declspec() *) 24 Extern = "import "; (* particularily introduced for VC++ declspec() *) 25 LocalScope = "_s"; (* name of a local intermediate scope (variable name) *) 26 GlobalScope = "_s"; (* pointer to current scope extension *) 27 LinkName = "lnk"; (* pointer to previous scope field *) 28 FlagExt = "__h"; 29 LenExt = "__len"; 30 DynTypExt = "__typ"; 31 TagExt = "__typ"; 32 Tab = 9X; 33 34 (* The following are defined as hex to avoid confusing editor syntax highlighting *) 35 Backslash = 5CX; 36 DoubleQuote = 22X; 37 38 39 VAR 40 indentLevel: INTEGER; 41 hashtab: ARRAY 105 OF SHORTINT; 42 keytab: ARRAY 50, 9 OF CHAR; 43 GlbPtrs: BOOLEAN; 44 BodyNameExt: ARRAY 13 OF CHAR; 45 46 47 PROCEDURE Init*; 48 BEGIN 49 indentLevel := 0; 50 BodyNameExt := "__init(void)" 51 END Init; 52 53 PROCEDURE Indent* (count: INTEGER); 54 BEGIN INC(indentLevel, count) 55 END Indent; 56 57 PROCEDURE BegStat*; 58 VAR i: INTEGER; 59 BEGIN i := indentLevel; 60 WHILE i > 0 DO OPM.Write(Tab); DEC (i) END 61 END BegStat; 62 63 PROCEDURE EndStat*; 64 BEGIN OPM.Write(';'); OPM.WriteLn 65 END EndStat; 66 67 PROCEDURE BegBlk*; 68 BEGIN OPM.Write('{'); OPM.WriteLn; INC(indentLevel) 69 END BegBlk; 70 71 PROCEDURE EndBlk*; 72 BEGIN DEC(indentLevel); BegStat; OPM.Write('}'); OPM.WriteLn 73 END EndBlk; 74 75 PROCEDURE EndBlk0*; 76 BEGIN DEC(indentLevel); BegStat; OPM.Write('}') 77 END EndBlk0; 78 79 PROCEDURE Str1(s: ARRAY OF CHAR; x: LONGINT); 80 VAR ch: CHAR; i: INTEGER; 81 BEGIN ch := s[0]; i := 0; 82 WHILE ch # 0X DO 83 IF ch = "#" THEN OPM.WriteInt(x) 84 ELSE OPM.Write(ch); 85 END ; 86 INC(i); ch := s[i] 87 END 88 END Str1; 89 90 PROCEDURE Length(VAR s: ARRAY OF CHAR): INTEGER; 91 VAR i: INTEGER; 92 BEGIN i := 0; 93 WHILE s[i] # 0X DO INC(i) END ; 94 RETURN i 95 END Length; 96 97 PROCEDURE PerfectHash (VAR s: ARRAY OF CHAR): INTEGER; 98 VAR i, h: INTEGER; 99 BEGIN i := 0; h := 0; 100 WHILE (s[i] # 0X) & (i < 5) DO h := 3*h + ORD(s[i]); INC(i) END; 101 RETURN h MOD 105 102 END PerfectHash; 103 104 PROCEDURE Ident* (obj: OPT.Object); 105 VAR mode, level, h: INTEGER; 106 BEGIN 107 mode := obj^.mode; level := obj^.mnolev; 108 IF (mode IN {OPT.Var, OPT.Typ, OPT.LProc}) & (level > 0) OR (mode IN {OPT.Fld, OPT.VarPar}) THEN 109 OPM.WriteStringVar(obj^.name); 110 h := PerfectHash(obj^.name); 111 IF hashtab[h] >= 0 THEN 112 IF keytab[hashtab[h]] = obj^.name THEN OPM.Write('_') END 113 END 114 ELSIF (mode = OPT.Typ) & (obj.typ.form IN {OPT.Int, OPT.Set}) THEN 115 IF obj.typ = OPT.adrtyp THEN OPM.WriteString("ADDRESS") 116 ELSE 117 IF obj.typ.form = OPT.Int THEN OPM.WriteString("INT") ELSE OPM.WriteString("UINT") END; 118 OPM.WriteInt(obj.typ.size*8) 119 END 120 ELSE 121 IF (mode # OPT.Typ) OR (obj^.linkadr # PredefinedType) THEN 122 IF mode = OPT.TProc THEN Ident(obj^.link^.typ^.strobj) 123 ELSIF level < 0 THEN (* use unaliased module name *) 124 OPM.WriteStringVar(OPT.GlbMod[-level].name); 125 IF OPM.currFile = OPM.HeaderFile THEN OPT.GlbMod[-level].vis := 1 (*include in header file*) END ; 126 ELSE OPM.WriteStringVar(OPM.modName) 127 END ; 128 OPM.Write('_') 129 ELSIF (obj = OPT.sysptrtyp^.strobj) 130 OR (obj = OPT.bytetyp^.strobj) THEN 131 OPM.WriteString("SYSTEM_") 132 END; 133 OPM.WriteStringVar(obj^.name); 134 END 135 END Ident; 136 137 PROCEDURE Stars (typ: OPT.Struct; VAR openClause: BOOLEAN); 138 VAR pointers: INTEGER; 139 BEGIN 140 openClause := FALSE; 141 IF ((typ^.strobj = NIL) OR (typ^.strobj^.name = "")) & (typ^.comp # OPT.Record) THEN 142 IF typ^.comp IN {OPT.Array, OPT.DynArr} THEN 143 Stars (typ^.BaseTyp, openClause); 144 openClause := (typ^.comp = OPT.Array) 145 ELSIF typ^.form = OPT.ProcTyp THEN 146 OPM.Write('('); OPM.Write('*') 147 ELSE 148 pointers := 0; 149 (*WHILE (typ^.strobj = NIL) & (typ^.form = OPT.Pointer) DO INC (pointers); typ := typ^.BaseTyp END ; 150 IF (typ^.comp # OPT.DynArr) & (pointers # 0) THEN Stars (typ, openClause) END ;*) 151 WHILE ((typ^.strobj = NIL) OR (typ^.strobj^.name = "")) & (typ^.form = OPT.Pointer) DO 152 INC (pointers); typ := typ^.BaseTyp 153 END ; 154 IF pointers > 0 THEN 155 IF typ^.comp # OPT.DynArr THEN Stars (typ, openClause) END ; 156 IF openClause THEN OPM.Write('('); openClause := FALSE END ; 157 WHILE pointers > 0 DO OPM.Write('*'); DEC (pointers) END 158 END 159 END 160 END 161 END Stars; 162 163 PROCEDURE ^AnsiParamList (obj: OPT.Object; showParamNames: BOOLEAN); 164 165 PROCEDURE DeclareObj(dcl: OPT.Object; scopeDef: BOOLEAN); 166 VAR 167 typ: OPT.Struct; 168 varPar, openClause: BOOLEAN; form, comp: INTEGER; 169 BEGIN 170 typ := dcl^.typ; 171 varPar := ((dcl^.mode = OPT.VarPar) & (typ^.comp # OPT.Array)) OR (typ^.comp = OPT.DynArr) OR scopeDef; 172 Stars(typ, openClause); 173 IF varPar THEN 174 IF openClause THEN OPM.Write('(') END ; 175 OPM.Write('*') 176 END ; 177 IF dcl.name # "" THEN Ident(dcl) END ; 178 IF varPar & openClause THEN OPM.Write(')') END ; 179 openClause := FALSE; 180 LOOP 181 form := typ^.form; 182 comp := typ^.comp; 183 IF ((typ^.strobj # NIL) & (typ^.strobj^.name # "")) OR (form = OPT.NoTyp) OR (comp = OPT.Record) THEN EXIT 184 ELSIF (form = OPT.Pointer) & (typ^.BaseTyp^.comp # OPT.DynArr) THEN 185 openClause := TRUE 186 ELSIF (form = OPT.ProcTyp) OR (comp IN {OPT.Array, OPT.DynArr}) THEN 187 IF openClause THEN OPM.Write(')'); openClause := FALSE END ; 188 IF form = OPT.ProcTyp THEN 189 OPM.Write(")"); AnsiParamList(typ^.link, FALSE); 190 EXIT 191 ELSIF comp = OPT.Array THEN 192 OPM.Write('['); OPM.WriteInt(typ^.n); OPM.Write(']') 193 END 194 ELSE 195 EXIT 196 END ; 197 typ := typ^.BaseTyp 198 END 199 END DeclareObj; 200 201 PROCEDURE Andent*(typ: OPT.Struct); (* ident of possibly anonymous record type *) 202 BEGIN 203 IF (typ^.strobj = NIL) OR (typ^.align >= 10000H) THEN 204 OPM.WriteStringVar(OPM.modName); Str1("__#", typ^.align DIV 10000H) 205 ELSE Ident(typ^.strobj) 206 END 207 END Andent; 208 209 PROCEDURE Undefined(obj: OPT.Object): BOOLEAN; 210 BEGIN 211 (* imported anonymous types have obj^.name = ""; 212 used e.g. for repeating inherited fields *) 213 RETURN (obj^.name = "") 214 OR (obj^.mnolev >= 0) 215 & (obj^.linkadr # 3+OPM.currFile ) 216 & (obj^.linkadr # PredefinedType) 217 END Undefined; 218 219 PROCEDURE ^FieldList (typ: OPT.Struct; last: BOOLEAN; VAR off, n, curAlign: LONGINT); 220 221 PROCEDURE DeclareBase(dcl: OPT.Object); (* declare the specifier of object dcl*) 222 VAR typ, prev: OPT.Struct; obj: OPT.Object; nofdims: INTEGER; off, n, dummy: LONGINT; 223 BEGIN 224 typ := dcl^.typ; prev := typ; 225 WHILE ((typ^.strobj = NIL) OR (typ^.comp = OPT.DynArr) OR Undefined(typ^.strobj)) 226 & (typ^.comp # OPT.Record) 227 & (typ^.form # OPT.NoTyp) 228 & ~((typ^.form = OPT.Pointer) & (typ^.BaseTyp^.comp = OPT.DynArr)) DO 229 prev := typ; typ := typ^.BaseTyp; 230 END ; 231 obj := typ^.strobj; 232 IF typ^.form = OPT.NoTyp THEN (* proper procedure *) 233 OPM.WriteString('void') 234 ELSIF (obj # NIL) & ~Undefined(obj) THEN (* named type, already declared *) 235 Ident(obj) 236 ELSIF typ^.comp = OPT.Record THEN 237 OPM.WriteString('struct '); Andent(typ); 238 IF (prev.form # OPT.Pointer) & ((obj # NIL) OR (dcl.name = "")) THEN 239 (* named record type not yet declared OR anonymous record with empty name *) 240 IF (typ^.BaseTyp # NIL) & (typ^.BaseTyp^.strobj.vis # OPT.internal) THEN 241 OPM.WriteString(" { /* "); Ident(typ^.BaseTyp^.strobj); OPM.WriteString(" */"); OPM.WriteLn; Indent(1) 242 ELSE OPM.Write(' '); BegBlk 243 END ; 244 FieldList(typ, TRUE, off, n, dummy); 245 EndBlk0 246 END 247 ELSIF (typ^.form = OPT.Pointer) & (typ^.BaseTyp^.comp = OPT.DynArr) THEN 248 typ := typ^.BaseTyp^.BaseTyp; nofdims := 1; 249 WHILE typ^.comp = OPT.DynArr DO INC(nofdims); typ := typ^.BaseTyp END ; 250 OPM.WriteString('struct '); BegBlk; 251 BegStat; Str1("ADDRESS len[#]", nofdims); EndStat; 252 BegStat; NEW(obj); NEW(obj.typ); (* aux. object for easy declaration *) 253 obj.typ.form := OPT.Comp; obj.typ.comp := OPT.Array; obj.typ.n := 1; obj.typ.BaseTyp := typ; obj.mode := OPT.Fld; obj.name := "data"; 254 obj.linkadr := UndefinedType; DeclareBase(obj); OPM.Write(' '); DeclareObj(obj, FALSE); 255 EndStat; EndBlk0 256 END 257 END DeclareBase; 258 259 PROCEDURE NofPtrs* (typ: OPT.Struct): LONGINT; 260 VAR fld: OPT.Object; btyp: OPT.Struct; n: LONGINT; 261 BEGIN 262 IF (typ^.form = OPT.Pointer) & (typ^.sysflag = 0) THEN RETURN 1 263 ELSIF (typ^.comp = OPT.Record) & (typ^.sysflag MOD 100H = 0) THEN 264 btyp := typ^.BaseTyp; 265 IF btyp # NIL THEN n := NofPtrs(btyp) ELSE n := 0 END ; 266 fld := typ^.link; 267 WHILE (fld # NIL) & (fld^.mode = OPT.Fld) DO 268 IF fld^.name # OPM.HdPtrName THEN n := n + NofPtrs(fld^.typ) 269 ELSE INC(n) 270 END ; 271 fld := fld^.link 272 END ; 273 RETURN n 274 ELSIF typ^.comp = OPT.Array THEN 275 btyp := typ^.BaseTyp; n := typ^.n; 276 WHILE btyp^.comp = OPT.Array DO n := btyp^.n * n; btyp := btyp^.BaseTyp END ; 277 RETURN NofPtrs(btyp) * n 278 ELSE RETURN 0 279 END 280 END NofPtrs; 281 282 PROCEDURE PutPtrOffsets (typ: OPT.Struct; adr: LONGINT; VAR cnt: LONGINT); 283 VAR fld: OPT.Object; btyp: OPT.Struct; n, i: LONGINT; 284 BEGIN 285 IF (typ^.form = OPT.Pointer) & (typ^.sysflag = 0) THEN 286 OPM.WriteInt(adr); OPM.WriteString(", "); INC(cnt); 287 IF cnt MOD 16 = 0 THEN OPM.WriteLn; OPM.Write(Tab) END 288 ELSIF (typ^.comp = OPT.Record) & (typ^.sysflag MOD 100H = 0) THEN 289 btyp := typ^.BaseTyp; 290 IF btyp # NIL THEN PutPtrOffsets(btyp, adr, cnt) END ; 291 fld := typ^.link; 292 WHILE (fld # NIL) & (fld^.mode = OPT.Fld) DO 293 IF fld^.name # OPM.HdPtrName THEN PutPtrOffsets(fld^.typ, adr + fld^.adr, cnt) 294 ELSE 295 OPM.WriteInt(adr + fld^.adr); OPM.WriteString(", "); INC(cnt); 296 IF cnt MOD 16 = 0 THEN OPM.WriteLn; OPM.Write(Tab) END 297 END ; 298 fld := fld^.link 299 END 300 ELSIF typ^.comp = OPT.Array THEN 301 btyp := typ^.BaseTyp; n := typ^.n; 302 WHILE btyp^.comp = OPT.Array DO n := btyp^.n * n; btyp := btyp^.BaseTyp END ; 303 IF NofPtrs(btyp) > 0 THEN i := 0; 304 WHILE i < n DO PutPtrOffsets(btyp, adr + i * btyp^.size, cnt); INC(i) END 305 END 306 END 307 END PutPtrOffsets; 308 309 PROCEDURE InitTProcs(typ, obj: OPT.Object); 310 BEGIN 311 IF obj # NIL THEN 312 InitTProcs(typ, obj^.left); 313 IF obj^.mode = OPT.TProc THEN 314 BegStat; 315 OPM.WriteString("__INITBP("); 316 Ident(typ); OPM.WriteString(', '); Ident(obj); 317 Str1(", #)", obj^.adr DIV 10000H); 318 EndStat 319 END ; 320 InitTProcs(typ, obj^.right) 321 END 322 END InitTProcs; 323 324 PROCEDURE PutBase(typ: OPT.Struct); 325 BEGIN 326 IF typ # NIL THEN 327 PutBase(typ^.BaseTyp); 328 Ident(typ^.strobj); OPM.WriteString(DynTypExt); OPM.WriteString(", ") 329 END 330 END PutBase; 331 332 PROCEDURE LenList(par: OPT.Object; ansiDefine, showParamName: BOOLEAN); 333 VAR typ: OPT.Struct; dim: INTEGER; 334 BEGIN 335 IF showParamName THEN Ident(par); OPM.WriteString(LenExt) END ; 336 dim := 1; typ := par^.typ^.BaseTyp; 337 WHILE typ^.comp = OPT.DynArr DO 338 IF ansiDefine THEN OPM.WriteString(", ADDRESS ") ELSE OPM.WriteString(', ') END ; 339 IF showParamName THEN Ident(par); OPM.WriteString(LenExt); OPM.WriteInt(dim) END ; 340 typ := typ^.BaseTyp; INC(dim) 341 END 342 END LenList; 343 344 PROCEDURE DeclareParams(par: OPT.Object; macro: BOOLEAN); 345 BEGIN 346 OPM.Write('('); 347 WHILE par # NIL DO 348 IF macro THEN OPM.WriteStringVar(par.name) 349 ELSE 350 IF (par^.mode = OPT.Var) & (par^.typ^.form = OPT.Real) THEN OPM.Write("_") END ; 351 Ident(par) 352 END ; 353 IF par^.typ^.comp = OPT.DynArr THEN 354 OPM.WriteString(', '); LenList(par, FALSE, TRUE); 355 ELSIF (par^.mode = OPT.VarPar) & (par^.typ^.comp = OPT.Record) THEN 356 OPM.WriteString(', '); OPM.WriteStringVar(par.name); OPM.WriteString(TagExt) 357 END ; 358 par := par^.link; 359 IF par # NIL THEN OPM.WriteString(', ') END 360 END ; 361 OPM.Write(')') 362 END DeclareParams; 363 364 PROCEDURE ^DefineType(str: OPT.Struct); 365 PROCEDURE ^ProcHeader(proc: OPT.Object; define: BOOLEAN); 366 367 PROCEDURE DefineTProcTypes(obj: OPT.Object); (* define all types that are used in a OPT.TProc definition *) 368 VAR par: OPT.Object; 369 BEGIN 370 IF obj^.typ # OPT.notyp THEN DefineType(obj^.typ) END ; 371 par := obj^.link; WHILE par # NIL DO DefineType(par^.typ); par := par^.link END 372 END DefineTProcTypes; 373 374 PROCEDURE DeclareTProcs(obj: OPT.Object; VAR empty: BOOLEAN); 375 BEGIN 376 IF obj # NIL THEN 377 DeclareTProcs(obj^.left, empty); 378 IF obj^.mode = OPT.TProc THEN 379 IF obj^.typ # OPT.notyp THEN DefineType(obj^.typ) END ; 380 IF OPM.currFile = OPM.HeaderFile THEN 381 IF obj^.vis = OPT.external THEN 382 DefineTProcTypes(obj); 383 OPM.WriteString(Extern); empty := FALSE; 384 ProcHeader(obj, FALSE) 385 END 386 ELSE empty := FALSE; 387 DefineTProcTypes(obj); 388 IF obj^.vis = OPT.internal THEN OPM.WriteString('static ') 389 ELSE OPM.WriteString(Export) 390 END ; 391 ProcHeader(obj, FALSE) 392 END 393 END ; 394 DeclareTProcs(obj^.right, empty) 395 END 396 END DeclareTProcs; 397 398 PROCEDURE BaseTProc*(obj: OPT.Object): OPT.Object; 399 VAR typ, base: OPT.Struct; mno: LONGINT; 400 BEGIN typ := obj^.link^.typ; (* receiver type *) 401 IF typ^.form = OPT.Pointer THEN typ := typ^.BaseTyp END ; 402 base := typ^.BaseTyp; mno := obj^.adr DIV 10000H; 403 WHILE (base # NIL) & (mno < base^.n) DO typ := base; base := typ^.BaseTyp END ; 404 OPT.FindField(obj^.name, typ, obj); 405 RETURN obj 406 END BaseTProc; 407 408 PROCEDURE DefineTProcMacros(obj: OPT.Object; VAR empty: BOOLEAN); 409 BEGIN 410 IF obj # NIL THEN 411 DefineTProcMacros(obj^.left, empty); 412 IF (obj^.mode = OPT.TProc) & (obj = BaseTProc(obj)) & ((OPM.currFile # OPM.HeaderFile) OR (obj^.vis = OPT.external)) THEN 413 OPM.WriteString("#define __"); 414 Ident(obj); 415 DeclareParams(obj^.link, TRUE); 416 OPM.WriteString(" __SEND("); 417 IF obj^.link^.typ^.form = OPT.Pointer THEN 418 OPM.WriteString("__TYPEOF("); Ident(obj^.link); OPM.Write(")") 419 ELSE Ident(obj^.link); OPM.WriteString(TagExt) 420 END ; 421 Str1(", #, ", obj^.adr DIV 10000H); 422 IF obj^.typ = OPT.notyp THEN OPM.WriteString('void') ELSE Ident(obj^.typ^.strobj) END ; 423 OPM.WriteString("(*)"); 424 AnsiParamList(obj^.link, FALSE); 425 OPM.WriteString(", "); 426 DeclareParams(obj^.link, TRUE); 427 OPM.Write(")"); OPM.WriteLn 428 END ; 429 DefineTProcMacros(obj^.right, empty) 430 END 431 END DefineTProcMacros; 432 433 PROCEDURE DefineType(str: OPT.Struct); (* define a type object *) 434 VAR obj, field, par: OPT.Object; empty: BOOLEAN; 435 BEGIN 436 IF (OPM.currFile = OPM.BodyFile) OR (str^.ref < OPM.MaxStruct (*for hidden exports*) ) THEN 437 obj := str^.strobj; 438 IF (obj = NIL) OR Undefined(obj) THEN 439 IF obj # NIL THEN (* check for cycles *) 440 IF obj^.linkadr = ProcessingType THEN 441 IF str^.form # OPT.Pointer THEN OPM.Mark(244, str^.txtpos); obj^.linkadr := PredefinedType END 442 ELSE obj^.linkadr := ProcessingType 443 END 444 END ; 445 IF str^.comp = OPT.Record THEN 446 (* the following exports the base type of an exported type even if the former is non-exported *) 447 IF str^.BaseTyp # NIL THEN DefineType(str^.BaseTyp) END ; 448 field := str^.link; 449 WHILE (field # NIL) & (field^.mode = OPT.Fld) DO 450 IF (field^.vis # OPT.internal) OR (OPM.currFile = OPM.BodyFile) THEN DefineType(field^.typ) END ; 451 field := field^.link 452 END 453 ELSIF str^.form = OPT.Pointer THEN 454 IF str^.BaseTyp^.comp # OPT.Record THEN DefineType(str^.BaseTyp) END 455 ELSIF str^.comp IN {OPT.Array, OPT.DynArr} THEN 456 IF (str^.BaseTyp^.strobj # NIL) & (str^.BaseTyp^.strobj^.linkadr = ProcessingType) THEN (*cyclic base type*) 457 OPM.Mark(244, str^ .txtpos); str^.BaseTyp^.strobj^.linkadr := PredefinedType 458 END ; 459 DefineType(str^.BaseTyp) 460 ELSIF str^.form = OPT.ProcTyp THEN 461 IF str^.BaseTyp # OPT.notyp THEN DefineType(str^.BaseTyp) END ; 462 field := str^.link; 463 WHILE field # NIL DO DefineType(field^.typ); field := field^.link END 464 END 465 END ; 466 IF (obj # NIL) & Undefined(obj) THEN 467 OPM.WriteString("typedef"); OPM.WriteLn; OPM.Write(Tab); Indent(1); 468 obj^.linkadr := ProcessingType; 469 DeclareBase(obj); OPM.Write(' '); 470 obj^.typ^.strobj := NIL; (* SG: trick to make DeclareObj declare the type *) 471 DeclareObj(obj, FALSE); 472 obj^.typ^.strobj := obj; (* SG: revert trick *) 473 obj^.linkadr := 3+OPM.currFile; 474 EndStat; Indent(-1); OPM.WriteLn; 475 IF obj^.typ^.comp = OPT.Record THEN empty := TRUE; 476 DeclareTProcs(str^.link, empty); DefineTProcMacros(str^.link, empty); 477 IF ~empty THEN OPM.WriteLn END 478 END 479 END 480 END 481 END DefineType; 482 483 PROCEDURE Prefixed(x: OPT.ConstExt; y: ARRAY OF CHAR): BOOLEAN; 484 VAR i: INTEGER; 485 BEGIN i := 0; 486 WHILE x[i+1] = y[i] DO INC(i) END; 487 RETURN y[i] = 0X; 488 END Prefixed; 489 490 PROCEDURE CProcDefs(obj: OPT.Object; vis: INTEGER); 491 VAR i: INTEGER; ext: OPT.ConstExt; 492 BEGIN 493 IF obj # NIL THEN 494 CProcDefs(obj^.left, vis); 495 (* bug: obj.history cannot be used to cover unexported and deleted CProcs; use special flag obj.adr = 1 *) 496 IF (obj^.mode = OPT.CProc) & (obj^.vis >= vis) & (obj^.adr = 1) THEN 497 ext := obj.conval.ext; i := 1; 498 IF (ext[1] # "#") & ~(Prefixed(ext, "extern ") OR Prefixed(ext, Extern)) THEN 499 OPM.WriteString("#define "); Ident(obj); 500 DeclareParams(obj^.link, TRUE); 501 OPM.Write(Tab); 502 END ; 503 FOR i := i TO ORD(obj.conval.ext[0]) DO OPM.Write(obj.conval.ext[i]) END; 504 OPM.WriteLn 505 END ; 506 CProcDefs(obj^.right, vis) 507 END 508 END CProcDefs; 509 510 PROCEDURE TypeDefs* (obj: OPT.Object; vis(*replaced by test on currFile in DefineType*): INTEGER); 511 BEGIN 512 IF obj # NIL THEN 513 TypeDefs(obj^.left, vis); 514 (* test typ.txtpos to skip types that have been unexported; obj.history # removed is not enough!*) 515 IF (obj^.mode = OPT.Typ) & (obj^.typ^.txtpos > 0) THEN DefineType(obj^.typ) END ; 516 TypeDefs(obj^.right, vis) 517 END 518 END TypeDefs; 519 520 PROCEDURE DefAnonRecs(n: OPT.Node); 521 VAR o: OPT.Object; typ: OPT.Struct; 522 BEGIN 523 WHILE (n # NIL) & (n^.class = OPT.Ninittd) DO 524 typ := n^.typ; 525 IF (typ^.strobj = NIL) & ((OPM.currFile = OPM.BodyFile) OR (typ.ref < OPM.MaxStruct)) THEN 526 DefineType(typ); (* declare base and field types, if any *) 527 NEW(o); o.typ := typ; o.name := ""; DeclareBase(o); EndStat; OPM.WriteLn 528 (* simply defines a named struct, but not a type; 529 o.name = "" signals field list expansion for DeclareBase in this very special case *) 530 END ; 531 n := n^.link 532 END 533 END DefAnonRecs; 534 535 PROCEDURE TDescDecl* (typ: OPT.Struct); 536 VAR nofptrs: LONGINT; 537 o: OPT.Object; 538 BEGIN 539 BegStat; OPM.WriteString("__TDESC("); 540 Andent(typ); 541 Str1(", #", typ^.n + 1); Str1(", #) = {__TDFLDS(", NofPtrs(typ)); 542 OPM.Write(DoubleQuote); 543 IF typ^.strobj # NIL THEN OPM.WriteStringVar(typ^.strobj^.name) END ; 544 OPM.Write(DoubleQuote); 545 Str1(', #), {', typ^.size); 546 nofptrs := 0; PutPtrOffsets(typ, 0, nofptrs); Str1("#}}", -(nofptrs + 1) * OPM.AddressSize); 547 EndStat 548 END TDescDecl; 549 550 PROCEDURE InitTDesc*(typ: OPT.Struct); 551 BEGIN 552 BegStat; OPM.WriteString("__INITYP("); 553 Andent(typ); OPM.WriteString(", "); 554 IF typ^.BaseTyp # NIL THEN Andent(typ^.BaseTyp) ELSE Andent(typ) END ; 555 Str1(", #)", typ^.extlev); 556 EndStat; 557 IF typ^.strobj # NIL THEN InitTProcs(typ^.strobj, typ^.link) END 558 END InitTDesc; 559 560 PROCEDURE FillGap(gap, off, align: LONGINT; VAR n, curAlign: LONGINT); 561 (* gap: Required gap - already calculated based on alignment requirements 562 off: Current offset - where gap begins 563 align: Containing record type alignment 564 n: Next ordinal to use for private field names 565 curAlign: Largest alignment of any field so far 566 *) 567 VAR adr: LONGINT; 568 BEGIN 569 adr := off; OPT.Align(adr, align); 570 IF (curAlign < align) & (gap - (adr - off) >= align) THEN (* preserve alignment of the enclosing struct! *) 571 DEC(gap, (adr - off) + align); 572 BegStat; 573 CASE align OF 574 |2: OPM.WriteString("INT16") 575 |4: OPM.WriteString("INT32") 576 |8: OPM.WriteString("INT64") 577 ELSE OPM.LogWLn; OPM.LogWStr("Unexpected enclosing alignment in FillGap.") 578 END; 579 Str1(" _prvt#", n); INC(n); EndStat; 580 curAlign := align 581 END ; 582 IF gap > 0 THEN BegStat; Str1("char _prvt#", n); INC(n); Str1("[#]", gap); EndStat END 583 END FillGap; 584 585 PROCEDURE FieldList (typ: OPT.Struct; last: BOOLEAN; VAR off, n, curAlign: LONGINT); 586 VAR fld: OPT.Object; base: OPT.Struct; gap, adr, align, fldAlign: LONGINT; 587 BEGIN 588 fld := typ.link; 589 align := typ^.align MOD 10000H; 590 IF typ.BaseTyp # NIL THEN FieldList(typ.BaseTyp, FALSE, off, n, curAlign) 591 ELSE off := 0; n := 0; curAlign := 1 592 END; 593 (* off: Current offset into record 594 align: Overall (RECORD) alignment 595 curAlign: Current alignment - largest alignment of any field so far 596 n: Next ordinal to use for private field names 597 *) 598 WHILE (fld # NIL) & (fld.mode = OPT.Fld) DO 599 IF (OPM.currFile = OPM.HeaderFile) & (fld.vis = OPT.internal) 600 OR (OPM.currFile = OPM.BodyFile) & (fld.vis = OPT.internal) & (typ^.mno # 0) THEN 601 (* Skip private fields *) 602 fld := fld.link; 603 WHILE (fld # NIL) & (fld.mode = OPT.Fld) & (fld.vis = OPT.internal) DO fld := fld.link END; 604 ELSE 605 (* mimic OPV.TypSize to detect gaps caused by private fields *) 606 adr := off; 607 fldAlign := OPT.BaseAlignment(fld^.typ); 608 OPT.Align(adr, fldAlign); 609 gap := fld.adr - adr; 610 IF fldAlign > curAlign THEN curAlign := fldAlign END; 611 IF gap > 0 THEN 612 FillGap(gap, off, align, n, curAlign) 613 END; 614 BegStat; DeclareBase(fld); OPM.Write(' '); DeclareObj(fld, FALSE); 615 off := fld.adr + fld.typ.size; base := fld.typ; fld := fld.link; 616 WHILE (fld # NIL) 617 & (fld.mode = OPT.Fld) 618 & (fld.typ = base) 619 & (fld.adr = off) 620(* ?? *) & ((OPM.currFile = OPM.BodyFile) OR (fld.vis # OPT.internal) OR (fld.typ.strobj = NIL)) DO 621 OPM.WriteString(", "); DeclareObj(fld, FALSE); off := fld.adr + fld.typ.size; fld := fld.link 622 END; 623 EndStat 624 END 625 END; 626 IF last THEN 627 adr := typ.size - typ^.sysflag DIV 100H; 628 IF adr = 0 THEN gap := 1 (* avoid empty struct *) ELSE gap := adr - off END ; 629 IF gap > 0 THEN FillGap(gap, off, align, n, curAlign) END 630 END 631 END FieldList; 632 633 PROCEDURE IdentList (obj: OPT.Object; vis: INTEGER); 634 (* generate var and param lists; vis: 0 all global vars, local var, 1 exported(R) var, 2 par list, 3 scope var *) 635 VAR base: OPT.Struct; first: BOOLEAN; lastvis: INTEGER; 636 BEGIN 637 base := NIL; first := TRUE; 638 WHILE (obj # NIL) & (obj^.mode # OPT.TProc) DO 639 IF (vis IN {0, 2}) OR ((vis = 1) & (obj^.vis # 0)) OR ((vis = 3) & ~obj^.leaf) THEN 640 IF (obj^.typ # base) OR (obj^.vis # lastvis) THEN (* new variable base type definition required *) 641 IF ~first THEN EndStat END ; 642 first := FALSE; 643 base := obj^.typ; lastvis := obj^.vis; 644 BegStat; 645 IF (vis = 1) & (obj^.vis # OPT.internal) THEN OPM.WriteString(Extern) 646 ELSIF (obj^.mnolev = 0) & (vis = 0) THEN 647 IF obj^.vis = OPT.internal THEN OPM.WriteString('static ') 648 ELSE OPM.WriteString(Export) 649 END 650 END ; 651 IF (vis = 2) & (obj^.mode = OPT.Var) & (base^.form = OPT.Real) THEN OPM.WriteString("double") 652 ELSE DeclareBase(obj) 653 END 654 ELSE OPM.Write(","); 655 END ; 656 OPM.Write(' '); 657 IF (vis = 2) & (obj^.mode = OPT.Var) & (base^.form = OPT.Real) THEN OPM.Write("_") END ; 658 DeclareObj(obj, vis = 3); 659 IF obj^.typ^.comp = OPT.DynArr THEN (* declare len parameter(s) *) 660 EndStat; BegStat; 661 base := OPT.adrtyp; 662 OPM.WriteString("ADDRESS "); LenList(obj, FALSE, TRUE) 663 ELSIF (obj^.mode = OPT.VarPar) & (obj^.typ^.comp = OPT.Record) THEN 664 EndStat; BegStat; 665 OPM.WriteString("ADDRESS *"); Ident(obj); OPM.WriteString(TagExt); 666 base := NIL 667 ELSIF (OPM.ptrinit IN OPM.Options) & (vis = 0) & (obj^.mnolev > 0) & (obj^.typ^.form = OPT.Pointer) THEN 668 OPM.WriteString(" = NIL") 669 END 670 END ; 671 obj := obj^.link 672 END ; 673 IF ~first THEN EndStat END 674 END IdentList; 675 676 PROCEDURE AnsiParamList (obj: OPT.Object; showParamNames: BOOLEAN); 677 VAR name: ARRAY 32 OF CHAR; 678 BEGIN 679 OPM.Write("("); 680 IF (obj = NIL) OR (obj^.mode = OPT.TProc) THEN OPM.WriteString("void") 681 ELSE 682 LOOP 683 DeclareBase(obj); 684 IF showParamNames THEN 685 OPM.Write(' '); DeclareObj(obj, FALSE) 686 ELSE 687 COPY(obj^.name, name); obj^.name := ""; DeclareObj(obj, FALSE); COPY(name, obj^.name) 688 END ; 689 IF obj^.typ^.comp = OPT.DynArr THEN 690 OPM.WriteString(", ADDRESS "); 691 LenList(obj, TRUE, showParamNames) 692 ELSIF (obj^.mode = OPT.VarPar) & (obj^.typ^.comp = OPT.Record) THEN 693 OPM.WriteString(", ADDRESS *"); 694 IF showParamNames THEN Ident(obj); OPM.WriteString(TagExt) END 695 END ; 696 IF (obj^.link = NIL) OR (obj^.link.mode = OPT.TProc) THEN EXIT END ; 697 OPM.WriteString(", "); 698 obj := obj^.link 699 END 700 END ; 701 OPM.Write(")") 702 END AnsiParamList; 703 704 PROCEDURE ProcHeader(proc: OPT.Object; define: BOOLEAN); 705 BEGIN 706 IF proc^.typ = OPT.notyp THEN OPM.WriteString('void') ELSE Ident(proc^.typ^.strobj) END ; 707 OPM.Write(' '); Ident(proc); OPM.Write(' '); 708 AnsiParamList(proc^.link, TRUE); 709 IF ~define THEN OPM.Write(";") END ; 710 OPM.WriteLn 711 END ProcHeader; 712 713 PROCEDURE ProcPredefs (obj: OPT.Object; vis: SHORTINT); (* forward declaration of procedures *) 714 BEGIN 715 IF obj # NIL THEN 716 ProcPredefs(obj^.left, vis); 717 IF (obj^.mode IN {OPT.LProc, OPT.XProc}) & (obj^.vis >= vis) & ((obj^.history # OPT.removed) OR (obj^.mode = OPT.LProc)) THEN 718 (* previous OPT.XProc may be deleted or become OPT.LProc after interface change*) 719 IF vis = OPT.external THEN OPM.WriteString(Extern) 720 ELSIF obj^.vis = OPT.internal THEN OPM.WriteString('static ') 721 ELSE OPM.WriteString(Export) 722 END ; 723 ProcHeader(obj, FALSE); 724 END ; 725 ProcPredefs(obj^.right, vis); 726 END; 727 END ProcPredefs; 728 729 PROCEDURE Include(name: ARRAY OF CHAR); 730 BEGIN 731 OPM.WriteString("#include "); OPM.Write(DoubleQuote); OPM.WriteStringVar(name); 732 OPM.WriteString(".h"); OPM.Write(DoubleQuote); OPM.WriteLn 733 END Include; 734 735 PROCEDURE IncludeImports(obj: OPT.Object; vis: INTEGER); 736 BEGIN 737 IF obj # NIL THEN 738 IncludeImports(obj^.left, vis); 739 IF (obj^.mode = OPT.Mod) & (obj^.mnolev # 0) & (OPT.GlbMod[-obj^.mnolev].vis >= vis) THEN (* @self and SYSTEM have mnolev = 0 *) 740 Include(OPT.GlbMod[-obj^.mnolev].name) (* use unaliased module name *) 741 END; 742 IncludeImports(obj^.right, vis); 743 END; 744 END IncludeImports; 745 746 PROCEDURE GenDynTypes (n: OPT.Node; vis: INTEGER); 747 VAR typ: OPT.Struct; 748 BEGIN 749 WHILE (n # NIL) & (n^.class = OPT.Ninittd) DO 750 typ := n^.typ; 751 IF (vis = OPT.internal) OR (typ^.ref < OPM.MaxStruct (*type needed in symbol file*)) THEN 752 BegStat; 753 IF vis = OPT.external THEN OPM.WriteString(Extern) 754 ELSIF (typ^.strobj # NIL) & (typ^.strobj^.mnolev > 0) THEN OPM.WriteString('static ') 755 ELSE OPM.WriteString(Export) 756 END ; 757 OPM.WriteString("ADDRESS *"); Andent(typ); OPM.WriteString(DynTypExt); 758 EndStat 759 END ; 760 n := n^.link 761 END 762 END GenDynTypes; 763 764 PROCEDURE GenHdr*(n: OPT.Node); 765 BEGIN 766 (* includes are delayed until it is known which ones are needed in the header *) 767 OPM.currFile := OPM.HeaderFile; 768 DefAnonRecs(n); 769 TypeDefs(OPT.topScope^.right, 1); OPM.WriteLn; 770 IdentList(OPT.topScope^.scope, 1); OPM.WriteLn; 771 GenDynTypes(n, OPT.external); OPM.WriteLn; 772 ProcPredefs(OPT.topScope^.right, 1); 773 OPM.WriteString(Extern); OPM.WriteString("void *"); 774 OPM.WriteStringVar(OPM.modName); OPM.WriteString(BodyNameExt); 775 EndStat; OPM.WriteLn; 776 CProcDefs(OPT.topScope^.right, 1); OPM.WriteLn; 777 OPM.WriteString("#endif // "); OPM.WriteStringVar(OPM.modName); OPM.WriteLn 778 END GenHdr; 779 780 PROCEDURE GenHeaderMsg; 781 VAR i: INTEGER; 782 BEGIN 783 OPM.WriteString("/* "); OPM.WriteString(Configuration.name); 784 OPM.Write(" "); OPM.WriteString(Configuration.versionLong); OPM.Write (" "); (* noch *) 785 FOR i := 0 TO MAX(SET) DO 786 IF i IN OPM.Options THEN 787 CASE i OF (* c.f. ScanOptions in OPM *) 788 | OPM.inxchk: OPM.Write("x") 789 | OPM.ranchk: OPM.Write("r") 790 | OPM.typchk: OPM.Write("t") 791 | OPM.newsf: OPM.Write("s") 792 | OPM.ptrinit: OPM.Write("p") 793 | OPM.assert: OPM.Write("a") 794 | OPM.extsf: OPM.Write("e") 795 | OPM.mainprog: OPM.Write("m") 796 | OPM.dontasm: OPM.Write("S") 797 | OPM.dontlink: OPM.Write("c") 798 | OPM.mainlinkstat: OPM.Write("M") 799 | OPM.notcoloroutput: OPM.Write("f") 800 | OPM.forcenewsym: OPM.Write("F") 801 | OPM.verbose: OPM.Write("v") 802 ELSE OPM.LogWStr ("( more options defined in OPM than checked in OPC.GenHeaderMsg, if you are a compiler developer, add them to OPC.GenHeaderMsg"); OPM.LogWLn; 803 END 804 END 805 END; 806 OPM.WriteString(" */"); OPM.WriteLn 807 END GenHeaderMsg; 808 809 PROCEDURE GenHdrIncludes*; 810 BEGIN 811 OPM.currFile := OPM.HeaderInclude; 812 GenHeaderMsg; 813 OPM.WriteLn; 814 OPM.WriteString("#ifndef "); OPM.WriteStringVar(OPM.modName); OPM.WriteString(FlagExt); OPM.WriteLn; 815 OPM.WriteString("#define "); OPM.WriteStringVar(OPM.modName); OPM.WriteString(FlagExt); OPM.WriteLn; 816 OPM.WriteLn; 817 818 Include(BasicIncludeFile); 819 IncludeImports(OPT.topScope^.right, 1); OPM.WriteLn 820 END GenHdrIncludes; 821 822 PROCEDURE GenBdy*(n: OPT.Node); 823 BEGIN 824 OPM.currFile := OPM.BodyFile; 825 GenHeaderMsg; 826 OPM.WriteLn; 827 828 (* Define model dependent type sizes *) 829 OPM.WriteString("#define SHORTINT INT"); OPM.WriteInt(OPT.sinttyp.size*8); OPM.WriteLn; 830 OPM.WriteString("#define INTEGER INT"); OPM.WriteInt(OPT.inttyp.size*8); OPM.WriteLn; 831 OPM.WriteString("#define LONGINT INT"); OPM.WriteInt(OPT.linttyp.size*8); OPM.WriteLn; 832 OPM.WriteString("#define SET UINT"); OPM.WriteInt(OPT.settyp.size*8); OPM.WriteLn; 833 OPM.WriteLn; 834 835 Include(BasicIncludeFile); 836 IncludeImports(OPT.topScope^.right, 0); OPM.WriteLn; 837 DefAnonRecs(n); 838 TypeDefs(OPT.topScope^.right, 0); OPM.WriteLn; 839 IdentList(OPT.topScope^.scope, 0); OPM.WriteLn; 840 GenDynTypes(n, OPT.internal); OPM.WriteLn; 841 ProcPredefs(OPT.topScope^.right, 0); OPM.WriteLn; 842 CProcDefs(OPT.topScope^.right, 0); OPM.WriteLn 843 END GenBdy; 844 845 PROCEDURE RegCmds(obj: OPT.Object); 846 BEGIN 847 IF obj # NIL THEN 848 RegCmds(obj^.left); 849 IF (obj^.mode = OPT.XProc) & (obj^.history # OPT.removed) THEN 850 IF (obj^.vis # 0) & (obj^.link = NIL) & (obj^.typ = OPT.notyp) THEN (*command*) 851 BegStat; OPM.WriteString('__REGCMD("'); 852 OPM.WriteStringVar(obj.name); OPM.WriteString('", '); Ident(obj); OPM.Write(")"); EndStat 853 END 854 END ; 855 RegCmds(obj^.right) 856 END 857 END RegCmds; 858 859 PROCEDURE InitImports(obj: OPT.Object); 860 BEGIN 861 IF obj # NIL THEN 862 InitImports(obj^.left); 863 IF (obj^.mode = OPT.Mod) & (obj^.mnolev # 0) THEN 864 BegStat; OPM.WriteString("__MODULE_IMPORT("); 865 OPM.WriteStringVar(OPT.GlbMod[-obj^.mnolev].name); 866 OPM.Write(')'); EndStat 867 END ; 868 InitImports(obj^.right) 869 END 870 END InitImports; 871 872 PROCEDURE GenEnumPtrs* (var: OPT.Object); 873 VAR typ: OPT.Struct; n: LONGINT; 874 BEGIN GlbPtrs := FALSE; 875 WHILE var # NIL DO 876 typ := var^.typ; 877 IF NofPtrs(typ) > 0 THEN 878 IF ~GlbPtrs THEN GlbPtrs := TRUE; 879 OPM.WriteString("static void EnumPtrs(void (*P)(void*))"); OPM.WriteLn; 880 BegBlk 881 END ; 882 BegStat; 883 IF typ^.form = OPT.Pointer THEN 884 OPM.WriteString("P("); Ident(var); OPM.Write(")"); 885 ELSIF typ^.comp = OPT.Record THEN 886 OPM.WriteString("__ENUMR(&"); Ident(var); OPM.WriteString(", "); 887 Andent(typ); OPM.WriteString(DynTypExt); Str1(", #", typ^.size); OPM.WriteString(", 1, P)") 888 ELSIF typ^.comp = OPT.Array THEN 889 n := typ^.n; typ := typ^.BaseTyp; 890 WHILE typ^.comp = OPT.Array DO n := n * typ^.n; typ := typ^.BaseTyp END ; 891 IF typ^.form = OPT.Pointer THEN 892 OPM.WriteString("__ENUMP("); Ident(var); Str1(", #, P)", n) 893 ELSIF typ^.comp = OPT.Record THEN 894 OPM.WriteString("__ENUMR("); Ident(var); OPM.WriteString(", "); 895 Andent(typ); OPM.WriteString(DynTypExt); Str1(", #", typ^.size); Str1(", #, P)", n) 896 END 897 END ; 898 EndStat 899 END ; 900 var := var^.link 901 END ; 902 IF GlbPtrs THEN 903 EndBlk; OPM.WriteLn 904 END 905 END GenEnumPtrs; 906 907 PROCEDURE EnterBody*; 908 BEGIN 909 OPM.WriteLn; OPM.WriteString(Export); 910 IF OPM.mainprog IN OPM.Options THEN 911 OPM.WriteString("int main(int argc, char **argv)"); OPM.WriteLn; 912 ELSE 913 OPM.WriteString("void *"); 914 OPM.WriteString(OPM.modName); OPM.WriteString(BodyNameExt); OPM.WriteLn; 915 END ; 916 BegBlk; BegStat; 917 IF OPM.mainprog IN OPM.Options THEN OPM.WriteString("__INIT(argc, argv)") ELSE OPM.WriteString("__DEFMOD") END ; 918 EndStat; 919 IF (OPM.mainprog IN OPM.Options) & demoVersion THEN BegStat; 920 OPM.WriteString('/*don`t do it!*/ printf("DEMO VERSION: DO NOT USE THIS PROGRAM FOR ANY COMMERCIAL PURPOSE\n")'); 921 EndStat 922 END ; 923 InitImports(OPT.topScope^.right); 924 BegStat; 925 IF OPM.mainprog IN OPM.Options THEN OPM.WriteString('__REGMAIN("') ELSE OPM.WriteString('__REGMOD("') END ; 926 OPM.WriteString(OPM.modName); 927 IF GlbPtrs THEN OPM.WriteString('", EnumPtrs)') ELSE OPM.WriteString('", 0)') END ; 928 EndStat; 929 IF OPM.modName # "SYSTEM" THEN RegCmds(OPT.topScope) END 930 END EnterBody; 931 932 PROCEDURE ExitBody*; 933 BEGIN 934 BegStat; 935 IF OPM.mainprog IN OPM.Options THEN OPM.WriteString("__FINI;") ELSE OPM.WriteString("__ENDMOD;") END ; 936 OPM.WriteLn; EndBlk 937 END ExitBody; 938 939 PROCEDURE DefineInter* (proc: OPT.Object); (* define intermediate scope record and variable *) 940 VAR scope: OPT.Object; 941 BEGIN 942 scope := proc^.scope; 943 OPM.WriteString('static '); OPM.WriteString('struct '); OPM.WriteStringVar(scope^.name); OPM.Write(' '); 944 BegBlk; 945 IdentList(proc^.link, 3); (* parameters *) 946 IdentList(scope^.scope, 3); (* local variables *) 947 BegStat; (* scope link field declaration *) 948 OPM.WriteString('struct '); OPM.WriteStringVar (scope^.name); 949 OPM.Write(' '); OPM.Write('*'); OPM.WriteString(LinkName); EndStat; 950 EndBlk0; OPM.Write(' '); 951 OPM.Write('*'); OPM.WriteStringVar (scope^.name); OPM.WriteString(GlobalScope); EndStat; OPM.WriteLn; 952 ProcPredefs (scope^.right, 0); 953 OPM.WriteLn; 954 END DefineInter; 955 956 PROCEDURE NeedsRetval*(proc: OPT.Object): BOOLEAN; (* aux. variable __retval needed for return *) 957 BEGIN (* simple rule; ignores DUPlicated value arrays because they use alloca. *) 958 RETURN (proc^.typ # OPT.notyp) & ~proc^.scope^.leaf 959 END NeedsRetval; 960 961 PROCEDURE EnterProc* (proc: OPT.Object); 962 VAR var, scope: OPT.Object; typ: OPT.Struct; dim: INTEGER; 963 BEGIN 964 IF proc^.vis # OPT.external THEN OPM.WriteString('static ') END ; 965 ProcHeader(proc, TRUE); 966 BegBlk; 967 scope := proc^.scope; 968 IdentList(scope^.scope, 0); 969 IF ~scope^.leaf THEN (* declare intermediate procedure scope record variable*) 970 BegStat; OPM.WriteString('struct '); OPM.WriteStringVar (scope^.name); 971 OPM.Write(' '); OPM.WriteString(LocalScope); EndStat 972 END ; 973 IF NeedsRetval(proc) THEN BegStat; Ident(proc^.typ^.strobj); OPM.WriteString(" __retval"); EndStat END; 974 var := proc^.link; 975 WHILE var # NIL DO (* declare copy of fixed size value array parameters *) 976 IF (var^.typ^.comp = OPT.Array) & (var^.mode = OPT.Var) THEN 977 BegStat; 978 IF var^.typ^.strobj = NIL THEN OPM.Mark(200, var^.typ^.txtpos) ELSE Ident(var^.typ^.strobj) END ; 979 OPM.Write(' '); Ident(var); OPM.WriteString("__copy"); 980 EndStat 981 END ; 982 var := var^.link 983 END ; 984 var := proc^.link; 985 WHILE var # NIL DO (* copy value array parameters *) 986 IF (var^.typ^.comp IN {OPT.Array, OPT.DynArr}) & (var^.mode = OPT.Var) & (var^.typ^.sysflag = 0) THEN 987 BegStat; 988 IF var^.typ^.comp = OPT.Array THEN 989 OPM.WriteString("__DUPARR("); 990 Ident(var); OPM.WriteString(', '); 991 IF var^.typ^.strobj = NIL THEN OPM.Mark(200, var^.typ^.txtpos) ELSE Ident(var^.typ^.strobj) END 992 ELSE 993 OPM.WriteString('__DUP('); 994 Ident(var); OPM.WriteString(', '); Ident(var); OPM.WriteString(LenExt); 995 typ := var^.typ^.BaseTyp; dim := 1; 996 WHILE typ^.comp = OPT.DynArr DO 997 OPM.WriteString(" * "); Ident(var); OPM.WriteString(LenExt); OPM.WriteInt(dim); 998 typ := typ^.BaseTyp; INC(dim) 999 END ; 1000 OPM.WriteString(', '); 1001 IF (typ^.strobj = NIL) THEN OPM.Mark(200, typ^.txtpos) 1002 ELSE Ident(typ^.strobj) 1003 END 1004 END ; 1005 OPM.Write(')'); EndStat 1006 END ; 1007 var := var^.link 1008 END ; 1009 IF ~scope^.leaf THEN 1010 var := proc^.link; (* copy addresses of parameters into local scope record *) 1011 WHILE var # NIL DO 1012 IF ~var^.leaf THEN (* only if used by a nested procedure *) 1013 BegStat; 1014 OPM.WriteString(LocalScope); OPM.Write('.'); Ident(var); 1015 OPM.WriteString(' = '); 1016 IF var^.typ^.comp IN {OPT.Array, OPT.DynArr} THEN OPM.WriteString("(void*)") 1017 (* K&R and ANSI differ in the type: array or element type*) 1018 ELSIF var^.mode # OPT.VarPar THEN OPM.Write("&") 1019 END ; 1020 Ident(var); 1021 IF var^.typ^.comp = OPT.DynArr THEN 1022 typ := var^.typ; dim := 0; 1023 REPEAT (* copy len(s) *) 1024 OPM.WriteString("; "); 1025 OPM.WriteString(LocalScope); OPM.Write('.'); Ident(var); OPM.WriteString(LenExt); 1026 IF dim # 0 THEN OPM.WriteInt(dim) END ; 1027 OPM.WriteString(' = '); Ident(var); OPM.WriteString(LenExt); 1028 IF dim # 0 THEN OPM.WriteInt(dim) END ; 1029 typ := typ^.BaseTyp 1030 UNTIL typ^.comp # OPT.DynArr; 1031 ELSIF (var^.mode = OPT.VarPar) & (var^.typ^.comp = OPT.Record) THEN 1032 OPM.WriteString("; "); 1033 OPM.WriteString(LocalScope); OPM.Write('.'); Ident(var); OPM.WriteString(TagExt); 1034 OPM.WriteString(' = '); Ident(var); OPM.WriteString(TagExt) 1035 END ; 1036 EndStat 1037 END; 1038 var := var^.link; 1039 END; 1040 var := scope^.scope; (* copy addresses of local variables into scope record *) 1041 WHILE var # NIL DO 1042 IF ~var^.leaf THEN (* only if used by a nested procedure *) 1043 BegStat; 1044 OPM.WriteString(LocalScope); OPM.Write('.'); Ident(var); OPM.WriteString(' = '); 1045 IF var^.typ^.comp # OPT.Array THEN OPM.Write("&") 1046 ELSE OPM.WriteString("(void*)") (* K&R and ANSI differ in the type: array or element type*) 1047 END ; 1048 Ident(var); EndStat 1049 END ; 1050 var := var^.link 1051 END; 1052 (* now link new scope *) 1053 BegStat; OPM.WriteString(LocalScope); OPM.Write('.'); OPM.WriteString(LinkName); 1054 OPM.WriteString(' = '); OPM.WriteStringVar(scope^.name); OPM.WriteString(GlobalScope); EndStat; 1055 BegStat; OPM.WriteStringVar(scope^.name); OPM.WriteString(GlobalScope); OPM.WriteString(' = '); 1056 OPM.Write("&"); OPM.WriteString(LocalScope); EndStat 1057 END 1058 END EnterProc; 1059 1060 PROCEDURE ExitProc*(proc: OPT.Object; eoBlock, implicitRet: BOOLEAN); 1061 VAR var: OPT.Object; indent: BOOLEAN; 1062 BEGIN 1063 indent := eoBlock; 1064 IF implicitRet & (proc^.typ # OPT.notyp) THEN 1065 OPM.Write(Tab); OPM.WriteString("__RETCHK;"); OPM.WriteLn 1066 ELSIF ~eoBlock OR implicitRet THEN 1067 IF ~proc^.scope^.leaf THEN 1068 (* link scope pointer of nested proc back to previous scope *) 1069 IF indent THEN BegStat ELSE indent := TRUE END ; 1070 OPM.WriteStringVar(proc^.scope^.name); OPM.WriteString(GlobalScope); 1071 OPM.WriteString(' = '); OPM.WriteString(LocalScope); OPM.Write('.'); OPM.WriteString(LinkName); 1072 EndStat 1073 END; 1074 (* delete array value parameters *) 1075 var := proc^.link; 1076 WHILE var # NIL DO 1077 IF (var^.typ^.comp = OPT.DynArr) & (var^.mode = OPT.Var) & (var^.typ^.sysflag = 0) THEN 1078 IF indent THEN BegStat ELSE indent := TRUE END ; 1079 OPM.WriteString('__DEL('); Ident(var); OPM.Write(')'); EndStat 1080 END ; 1081 var := var^.link 1082 END 1083 END ; 1084 IF eoBlock THEN EndBlk; OPM.WriteLn 1085 ELSIF indent THEN BegStat 1086 END 1087 END ExitProc; 1088 1089 PROCEDURE CompleteIdent*(obj: OPT.Object); 1090 VAR comp, level: INTEGER; 1091 BEGIN 1092 (* obj^.mode IN {OPT.Var, OPT.VarPar} *) 1093 level := obj^.mnolev; 1094 IF obj^.adr = 1 THEN (* WITH-variable *) 1095 IF obj^.typ^.comp = OPT.Record THEN Ident(obj); OPM.WriteString("__") 1096 ELSE (* cast with guard pointer type *) 1097 OPM.WriteString("(*("); Ident(obj^.typ^.strobj); OPM.WriteString("*)&"); Ident(obj); OPM.Write(")") 1098 END 1099 ELSIF (level # OPM.level) & (level > 0) THEN (* intermediate var *) 1100 comp := obj^.typ^.comp; 1101 IF (obj^.mode # OPT.VarPar) & (comp # OPT.DynArr) THEN OPM.Write('*'); END; 1102 OPM.WriteStringVar(obj^.scope^.name); OPM.WriteString(GlobalScope); 1103 OPM.WriteString("->"); Ident(obj) 1104 ELSE 1105 Ident(obj) 1106 END 1107 END CompleteIdent; 1108 1109 PROCEDURE TypeOf*(ap: OPT.Object); 1110 VAR i: INTEGER; 1111 BEGIN 1112 ASSERT(ap.typ.comp = OPT.Record); 1113 IF ap.mode = OPT.VarPar THEN 1114 IF ap.mnolev # OPM.level THEN (*intermediate level var-par record; possible WITH-guarded*) 1115 OPM.WriteStringVar(ap^.scope^.name); OPM.WriteString("_s->"); Ident(ap) 1116 ELSE (*local var-par record*) 1117 Ident(ap) 1118 END ; 1119 OPM.WriteString(TagExt) 1120 ELSIF ap^.typ^.strobj # NIL THEN 1121 Ident(ap^.typ^.strobj); OPM.WriteString(DynTypExt) 1122 ELSE Andent(ap.typ) (*anonymous ap type, p^ *) 1123 END 1124 END TypeOf; 1125 1126 PROCEDURE Cmp*(rel: INTEGER); 1127 BEGIN 1128 CASE rel OF 1129 | OPT.eql: OPM.WriteString(" == ") 1130 | OPT.neq: OPM.WriteString(" != ") 1131 | OPT.lss: OPM.WriteString(" < ") 1132 | OPT.leq: OPM.WriteString(" <= ") 1133 | OPT.gtr: OPM.WriteString(" > ") 1134 | OPT.geq: OPM.WriteString(" >= ") 1135 ELSE OPM.LogWStr("unhandled case in OPC.Cmp, rel = "); OPM.LogWNum(rel, 0); OPM.LogWLn; 1136 END; 1137 END Cmp; 1138 1139 PROCEDURE CharacterLiteral(c: SYSTEM.INT64); 1140 BEGIN 1141 IF (c < 32) OR (c > 126) THEN 1142 OPM.WriteString("0x"); OPM.WriteHex(c) 1143 ELSE 1144 OPM.Write("'"); 1145 IF (c = ORD(Backslash)) OR (c = ORD("'")) OR (c = ORD("?")) THEN 1146 OPM.Write(Backslash) 1147 END; 1148 OPM.Write(CHR(c)); 1149 OPM.Write("'") 1150 END 1151 END CharacterLiteral; 1152 1153 PROCEDURE StringLiteral(s: ARRAY OF CHAR; l: LONGINT); 1154 VAR i: LONGINT; c: INTEGER; 1155 BEGIN 1156 OPM.Write(DoubleQuote); 1157 i := 0; WHILE i < l DO 1158 c := ORD(s[i]); 1159 IF (c < 32) OR (c > 126) THEN 1160 (* Encode binary character value using exactly 3 octal digits. 1161 Use octal in preference to hex as only the octal escape 1162 syntax ensures a subsequent character will not be absorbed 1163 into this literal. *) 1164 OPM.Write(Backslash); 1165 OPM.Write(CHR(ORD("0") + c DIV 64)); c := c MOD 64; 1166 OPM.Write(CHR(ORD("0") + c DIV 8)); c := c MOD 8; 1167 OPM.Write(CHR(ORD("0") + c)) 1168 ELSE 1169 IF (c = ORD(Backslash)) OR (c = ORD(DoubleQuote)) OR (c = ORD("?")) THEN 1170 OPM.Write(Backslash) 1171 END; 1172 OPM.Write(CHR(c)); 1173 END; 1174 INC(i); 1175 END; 1176 OPM.Write(DoubleQuote) 1177 END StringLiteral; 1178 1179 PROCEDURE Case*(caseVal: SYSTEM.INT64; form: INTEGER); 1180 VAR 1181 ch: CHAR; 1182 BEGIN 1183 OPM.WriteString('case '); 1184 CASE form OF 1185 | OPT.Char: CharacterLiteral(caseVal) 1186 | OPT.Int: OPM.WriteInt(caseVal); 1187 ELSE OPM.LogWStr("unhandled case in OPC.Case, form = "); OPM.LogWNum(form, 0); OPM.LogWLn; 1188 END; 1189 OPM.WriteString(': '); 1190 END Case; 1191 1192 PROCEDURE SetInclude* (exclude: BOOLEAN); 1193 BEGIN 1194 IF exclude THEN OPM.WriteString(" &= ~"); ELSE OPM.WriteString(" |= "); END; 1195 END SetInclude; 1196 1197 PROCEDURE Increment* (decrement: BOOLEAN); 1198 BEGIN 1199 IF decrement THEN OPM.WriteString(" -= "); ELSE OPM.WriteString(" += "); END; 1200 END Increment; 1201 1202 PROCEDURE Halt* (n: LONGINT); 1203 BEGIN 1204 Str1("__HALT(#)", n) 1205 END Halt; 1206 1207 PROCEDURE IntLiteral*(n: SYSTEM.INT64; size: LONGINT); 1208 BEGIN 1209 IF (size > OPM.CIntSize) & (n <= OPM.CIntMax) & (n > OPM.CIntMin) THEN 1210 OPM.WriteString("((INT"); OPM.WriteInt(size*8); OPM.WriteString(")("); 1211 OPM.WriteInt(n); OPM.WriteString("))") 1212 ELSE 1213 OPM.WriteInt(n) 1214 END 1215 END IntLiteral; 1216 1217 PROCEDURE Len* (obj: OPT.Object; array: OPT.Struct; dim: SYSTEM.INT64); 1218 VAR 1219 d: SYSTEM.INT64; 1220 BEGIN 1221 d := dim; 1222 WHILE d > 0 DO array := array^.BaseTyp; DEC(d) END; 1223 IF array^.comp = OPT.DynArr THEN 1224 CompleteIdent(obj); OPM.WriteString(LenExt); 1225 IF dim # 0 THEN OPM.WriteInt(dim) END 1226 ELSE (* array *) 1227 OPM.WriteInt(array.n) 1228 END 1229 END Len; 1230 1231 PROCEDURE Constant* (con: OPT.Const; form: INTEGER); 1232 VAR i: INTEGER; s: SYSTEM.SET64; 1233 hex: SYSTEM.INT64; skipLeading: BOOLEAN; 1234 BEGIN 1235 CASE form OF 1236 | OPT.Byte: OPM.WriteInt(con^.intval) 1237 | OPT.Bool: OPM.WriteInt(con^.intval) 1238 | OPT.Char: CharacterLiteral(con.intval) 1239 | OPT.Int: OPM.WriteInt(con^.intval) 1240 | OPT.Real: OPM.WriteReal(con^.realval, "f") 1241 | OPT.LReal: OPM.WriteReal(con^.realval, 0X) 1242 | OPT.Set: OPM.WriteString("0x"); 1243 skipLeading := TRUE; 1244 s := con^.setval; i := MAX(SYSTEM.SET64) + 1; 1245 REPEAT 1246 hex := 0; 1247 REPEAT 1248 DEC(i); hex := 2 * hex; 1249 IF i IN s THEN INC(hex) END 1250 UNTIL i MOD 8 = 0; 1251 IF (hex # 0) OR ~skipLeading THEN 1252 OPM.WriteHex(hex); 1253 skipLeading := FALSE 1254 END 1255 UNTIL i = 0; 1256 IF skipLeading THEN OPM.Write("0") END 1257 | OPT.String: StringLiteral(con.ext^, con.intval2-1) 1258 | OPT.NilTyp: OPM.WriteString('NIL'); 1259 ELSE OPM.LogWStr("unhandled case in OPC.Constant, form = "); OPM.LogWNum(form, 0); OPM.LogWLn; 1260 END; 1261 END Constant; 1262 1263 1264 PROCEDURE InitKeywords; 1265 VAR n, i: SHORTINT; 1266 1267 PROCEDURE Enter(s: ARRAY OF CHAR); 1268 VAR h: INTEGER; 1269 BEGIN h := PerfectHash(s); hashtab[h] := n; COPY(s, keytab[n]); INC(n) 1270 END Enter; 1271 1272 BEGIN n := 0; 1273 FOR i := 0 TO LEN(hashtab)-1 DO hashtab[i] := -1 END ; 1274 Enter("ADDRESS"); (* pseudo keyword used by voc *) 1275 Enter("INT16"); (* pseudo keyword used by voc *) 1276 Enter("INT32"); (* pseudo keyword used by voc *) 1277 Enter("INT64"); (* pseudo keyword used by voc *) 1278 Enter("INT8"); (* pseudo keyword used by voc *) 1279 Enter("UINT16"); (* pseudo keyword used by voc *) 1280 Enter("UINT32"); (* pseudo keyword used by voc *) 1281 Enter("UINT64"); (* pseudo keyword used by voc *) 1282 Enter("UINT8"); (* pseudo keyword used by voc *) 1283 1284 Enter("asm"); 1285 Enter("auto"); 1286 Enter("break"); 1287 Enter("case"); 1288 Enter("char"); 1289 Enter("const"); 1290 Enter("continue"); 1291 Enter("default"); 1292 Enter("do"); 1293 Enter("double"); 1294 Enter("else"); 1295 Enter("enum"); 1296 Enter("extern"); 1297 Enter("export"); (* pseudo keyword used by voc *) 1298 Enter("float"); 1299 Enter("for"); 1300 Enter("fortran"); 1301 Enter("goto"); 1302 Enter("if"); 1303 Enter("import"); (* pseudo keyword used by voc *) 1304 Enter("int"); 1305 Enter("long"); 1306 Enter("register"); 1307 Enter("return"); 1308 Enter("short"); 1309 Enter("signed"); 1310 Enter("sizeof"); 1311 Enter("size_t"); 1312 Enter("static"); 1313 Enter("struct"); 1314 Enter("switch"); 1315 Enter("typedef"); 1316 Enter("union"); 1317 Enter("unsigned"); 1318 Enter("void"); 1319 Enter("volatile"); 1320 Enter("while"); 1321 1322(* what about common predefined names from cpp as e.g. 1323 Operating System: ibm, gcos, os, tss and unix 1324 Hardware: interdata, pdp11, u370, u3b, 1325 u3b2, u3b5, u3b15, u3b20d, 1326 vax, ns32000, iAPX286, i386, 1327 sparc , and sun 1328 UNIX system variant: 1329 RES, and RT 1330 The lint(1V) command: 1331 lint 1332 *) 1333 END InitKeywords; 1334 1335BEGIN InitKeywords 1336END OPC. 1337