LupineUserInterfaceImpl.mesa.
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last edited by BZM on 2-May-82 23:18:33.
Last Edited by: Birrell, September 14, 1983 8:22 am
Last Edited by: Swinehart, July 3, 1984 1:50:25 pm PDT
Bob Hagmann February 8, 1985 5:06:48 pm PST
DIRECTORY
Ascii USING [CR, LF, SP, TAB ],
Commander USING [CommandProc, Register],
IO,
Loader USING [BCDBuildTime],
LupineManager USING [ErrorHandlerProc, Language, Options, OptionsRec, ParamPassingMethod, String, TranslateRemoteInterface],
Rope USING[ Equal, Fetch, Length, ROPE ];
LupineUserInterfaceImpl: CEDAR MONITOR
IMPORTS Commander, IO, Loader, LupineManager, Rope =
BEGIN
inUse: BOOLFALSE;
finished: CONDITION;
Wait: ENTRY PROC[out: IO.STREAM] =
BEGIN
ENABLE UNWIND => NULL;
wait: BOOL = inUse;
IF wait THEN out.PutRope["Waiting for other use of Lupine to finish ... "];
WHILE inUse DO WAIT finished ENDLOOP;
inUse ← TRUE;
IF wait THEN out.PutRope["ok\n"];
END;
Finish: ENTRY PROC =
{ inUse ← FALSE; NOTIFY finished };
DoIt: Commander.CommandProc--cmd: Commander.Handle-- =
BEGIN
in: IO.STREAM = cmd.in;
out: IO.STREAM = cmd.out;
targetLanguage: LupineManager.Language ← Cedar;
defaultParamPassing: LupineManager.ParamPassingMethod ← Value;
interMdsCalls: BOOLFALSE;
freeServerArgs: BOOLTRUE;
inlineDispatcherStubs: BOOLTRUE;
inlineMarshal: BOOLTRUE;
inlinePacketAllocateCount: INT ← 1000;
inlineRopeMarshal: BOOLTRUE;
declareSignals: BOOLTRUE;
warnMDSAllocs: BOOLTRUE;
importMultiple: BOOLTRUE;
maxHeapAllocs: INT ← 50;
maxMdsAllocs: INT ← 50;
lineLength: INT ← 82;
noClientModulesOut: INT ← 1;
CheckAbort: PROC =
{};
MyBreak: IO.BreakProc =
BEGIN
SELECT char FROM
Ascii.SP, Ascii.CR, Ascii.TAB, Ascii.LF, ', => RETURN[sepr];
'[, '], ', => RETURN[break];
ENDCASE => RETURN[other];
END;
SyntaxError: ERROR = CODE;
ParseLine: PROC[commandStr: IO.STREAM] =
BEGIN
GetToken: PROC RETURNS[Rope.ROPE] =
{ RETURN[ commandStr.GetTokenRope[MyBreak].token ] };
nextToken: Rope.ROPENIL;
DO key: Rope.ROPE;
args: LIST OF Rope.ROPENIL;
argCount: INT ← 0;
IF nextToken = NIL THEN nextToken ← GetToken[ ! IO.EndOfStream => EXIT];
key ← nextToken; nextToken ← NIL;
IF key.Equal[","] THEN LOOP;
IF key.Length[] = 0 THEN EXIT -- end of stream! --;
nextToken ← GetToken[ ! IO.EndOfStream => { nextToken ← NIL; CONTINUE } ];
IF nextToken.Equal["["]
THEN BEGIN
DO nextToken ← GetToken[ ! IO.EndOfStream => GOTO missingClose];
IF nextToken.Equal["]"] THEN EXIT;
IF nextToken.Equal[","] THEN LOOP;
IF args = NIL
THEN args ← CONS[first: nextToken, rest: NIL]
ELSE args.rest ← CONS[first: nextToken, rest: NIL];
argCount ← argCount+1;
ENDLOOP;
nextToken ← NIL;
EXITS missingClose =>
{ out.PutF["Missing \"]\"\n"]; ERROR SyntaxError[] };
END;
DoCommand[key, args, argCount];
ENDLOOP;
END;
DoCommand: PROC[key: Rope.ROPE, args: LIST OF Rope.ROPE, argCount: INT] =
BEGIN
SELECT TRUE FROM
key.Equal["Help", FALSE] =>
{ Help[] };
key.Equal["TranslateInterface", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; TranslateInterface[args.first] };
key.Equal["TargetLanguage", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetTargetLanguage[args.first] };
key.Equal["DefaultParameterPassing", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetParameterPassing[args.first] };
key.Equal["InterMdsCalls", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetInterMdsCalls[args.first] };
key.Equal["FreeServerArguments", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetFreeServerArgs[args.first] };
key.Equal["InlineDispatcherStubs", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetInlineStubs[args.first] };
key.Equal["InlineMarshal", TRUE] =>
{ IF argCount # 1 THEN GOTO wrong; SetInlineMarshal[args.first] };
key.Equal["InlineRopeMarshal", TRUE] =>
{ IF argCount # 1 THEN GOTO wrong; SetInlineRopeMarshal[args.first] };
key.Equal["DynamicHeapNEWs", FALSE] =>
{ IF argCount # 2 THEN GOTO wrong; SetDynamicHeapNEWs[args.first, args.rest.first] };
key.Equal["LineLength", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetLineLength[args.first] };
key.Equal["DeclareSignals", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetDeclareSignals[args.first] };
key.Equal["WarnMDSAllocs", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetWarnMDSAllocs[args.first] };
key.Equal["ImportSingle", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetImportSingle[args.first] };
key.Equal["InlinePacketAllocate", TRUE] =>
{ IF argCount # 1 THEN GOTO wrong; SetInlinePacketAllocate[args.first] };
key.Equal["GeneratedClientModules", FALSE] =>
{ IF argCount # 1 THEN GOTO wrong; SetGeneratedClientModules[args.first] };
argCount = 0 => TranslateInterface[key];
ENDCASE =>
{ out.PutF["Unknown command \"%g\"\n", [rope[key]]]; ERROR SyntaxError[] };
EXITS wrong =>
{ out.PutF["Wrong number of arguments to the \"%g\" command\n", [rope[key]]];
ERROR SyntaxError[] };
END;
Help: PROC =
BEGIN
out.PutRope["Lupine accepts command lines of the form:

Lupine command[args] command[args] command[args] . . .

The following commands are available (\"TranslateInterface[module]\" may be shortened to \"module\").

Help[]
-- prints this message
TranslateInterface[interfaceName]
-- produces the RPC stubs modules for that interface
TargetLanguage[{Cedar,Mesa} ← Cedar]
-- allows production of Pilot-compatible stubs
-- (which can't be run under Cedar)"];
out.PutRope["
DefaultParameterPassing[{Var, Value, Result, Handle} ← Value]
-- default parameter passing mode
InterMdsCalls[BOOL ← FALSE]
-- produces stubs for non-remote calls (archaic?)
FreeServerArguments[BOOL ← TRUE]
-- \"FALSE\" prevents de-allocation of POINTER
-- referents after server procedure calls
InlineDispatcherStubs[BOOL ← TRUE]
-- \"FALSE\" is needed for large interfaces to prevent
-- compiler storage overflow
InlineMarshal[BOOL ← TRUE]
-- \"FALSE\" produces a marshalling procedure per type.
-- This can save code size at the expense of speed.
InlineRopeMarshal[BOOL ← TRUE]
-- \"FALSE\" produces prodedure calls for ROPE marshalling.
-- This can save code size at the expense of speed.
InlinePacketAllocate[BOOL ← TRUE | INT]
-- \"FALSE\" does a procedure call to allocate packet buffers
-- greater than 64 words, while \"TRUE\" does the normal case
-- inline, and resorts to the procedure call for special cases.
-- An INT is the count of inline allocates to do.
DynamicHeapNEWs[long: INT ← 50, short: INT ← 50]
-- limit on dynamic storage allocations for
-- (LONG) POINTER referents.
LineLength[INT ← 82]
-- length of lines produced in stub sources
ImportSingle[BOOL ← FALSE]
-- \"TRUE\" means that this interface will always have a
single \"instance\" on the client's machine
DeclareSignals[BOOL ← TRUE]
-- \"FALSE\" means someone else will declare
-- (and export) the interface's signals
WarnMDSAllocs[BOOL ← TRUE]
-- \"FALSE\" means suppress warnings about
-- short POINTER (\"MDS\") allocations (Mesa only)
"];
END;
From failed attempt to all multiple output modules to rpcclientimpl
GeneratedClientModules[CARDINAL [1..9] ← 1],
-- split generated client module (e.g., TargetRpcClientImpl)
-- If more than one, imbed digit after \"Client\" in name.
TranslateInterface: PROCEDURE [interfaceFile: Rope.ROPE] =
BEGIN
aborted, errors, warnings: BOOLEANFALSE;
translateOptions: LupineManager.Options;
HandleError: LupineManager.ErrorHandlerProc =
PROCEDURE [type: ErrorType, code: ErrorCode,
codeExplanation: String,
outputFileName: String←StringNIL,
outputFileCharPosition: LONG INTEGER,
problemCausingText: String←NIL ]
RETURNS [abortTranslation: BOOLEAN�LSE];
BEGIN
CheckAbort[];
out.PutChar['\n];
SELECT type FROM
abort => { aborted ← TRUE; out.PutRope["\nFatal error"] };
error => { errors ← TRUE; out.PutRope["\nError"] };
warning => { warnings ← TRUE; out.PutRope["\nWarning"] };
ENDCASE => NULL;
IF outputFileName.Length[] # 0
THEN out.PutF[" at %g[%g]", [rope[outputFileName]], [integer[outputFileCharPosition]]];
out.PutF[":\n %g", [rope[codeExplanation]]];
IF problemCausingText.Length[] # 0
THEN out.PutF["\n Problem-causing file, module, identifier, or type: %g",
[rope[problemCausingText]] ];
RETURN [abortTranslation: FALSE];
END; -- HandleError.
CheckAbort[];
out.PutF["Translating %g ... ", [rope[interfaceFile]] ];
translateOptions ← NEW [ LupineManager.OptionsRec ← [
targetLanguage: targetLanguage,
defaultParamPassing: (IF interMdsCalls THEN InterMds ELSE defaultParamPassing),
freeServerArguments: freeServerArgs,
inlineServerDispatcherStubs: inlineDispatcherStubs,
inlineMarshal: inlineMarshal,
inlinePacketAllocateCount: inlinePacketAllocateCount,
inlineRopeMarshal: inlineRopeMarshal,
declareSignals: declareSignals,
warnMDSAllocs: warnMDSAllocs,
importMultiple: importMultiple,
noClientModulesOut: noClientModulesOut,
maxHeapAllocations: maxHeapAllocs,
maxMdsAllocations: maxMdsAllocs ] ];
TRUSTED{ LupineManager.TranslateRemoteInterface[
interfaceBcdFilename: interfaceFile,
errorHandler: HandleError,
options: translateOptions,
desiredLineLength: lineLength ] };
IF aborted OR errors OR warnings THEN out.PutChar['\n];
out.PutF["\nTranslation of %g %g.\n",
[rope[interfaceFile]],
[rope[SELECT TRUE FROM
aborted => "aborted",
errors => "finished with errors",
warnings => "finished with warnings",
ENDCASE => "complete"]] ];
END; -- TranslateInterface.
Bool: PROC[arg: Rope.ROPE, complain: BOOLTRUE] RETURNS[BOOL] =
BEGIN
SELECT TRUE FROM
Rope.Equal[arg, "TRUE", FALSE] => RETURN[TRUE];
Rope.Equal[arg, "FALSE", FALSE] => RETURN[FALSE];
ENDCASE => { IF complain THEN out.PutRope["\"TRUE\" or \"FALSE\" expected\n"]; ERROR SyntaxError[] };
END;
Int: PROC[arg: Rope.ROPE, complain: BOOLTRUE] RETURNS[val: INT ← 0] =
BEGIN
FOR i: CARDINAL IN CARDINAL[0..arg.Length[])
DO c: CHAR = arg.Fetch[i];
IF c IN ['0..'9]
THEN val ← val * 10 + (c-'0)
ELSE {
IF complain THEN out.PutRope["Decimal number expected\n"];
ERROR SyntaxError[];
};
ENDLOOP;
END;
SetTargetLanguage: PROCEDURE [language: Rope.ROPE] =
BEGIN
SELECT TRUE FROM
Rope.Equal[language, "Cedar", FALSE] => targetLanguage ← Cedar;
Rope.Equal[language, "Mesa", FALSE] => targetLanguage ← Mesa;
ENDCASE => { out.PutRope["Unknown target language\n"]; ERROR SyntaxError[] };
END;
SetParameterPassing: PROCEDURE [kind: Rope.ROPE] =
BEGIN
SELECT TRUE FROM
Rope.Equal[kind, "VAR", FALSE] => defaultParamPassing ← Var;
Rope.Equal[kind, "VALUE", FALSE] => defaultParamPassing ← Value;
Rope.Equal[kind, "RESULT", FALSE] => defaultParamPassing ← Result;
Rope.Equal[kind, "HANDLE", FALSE] => defaultParamPassing ← Handle;
ENDCASE => { out.PutRope["Unknown parameter mode\n"]; ERROR SyntaxError[] };
END;
SetInterMdsCalls: PROCEDURE [onOff: Rope.ROPE] =
{ interMdsCalls ← Bool[onOff] };
SetFreeServerArgs: PROCEDURE [onOff: Rope.ROPE] =
{ freeServerArgs ← Bool[onOff] };
SetInlineStubs: PROCEDURE [onOff: Rope.ROPE] =
{ inlineDispatcherStubs ← Bool[onOff] };
SetInlineMarshal: PROCEDURE [onOff: Rope.ROPE] =
{ inlineMarshal ← Bool[onOff] };
SetInlinePacketAllocate: PROCEDURE [onOff: Rope.ROPE] = {
tryForInt: BOOLFALSE;
inlinePacketAllocate: BOOLFALSE;
inlinePacketAllocate ← Bool[onOff, FALSE
! SyntaxError => {tryForInt ← TRUE; CONTINUE}];
IF tryForInt THEN {
intBad: BOOLFALSE;
inlinePacketAllocateCount ← Int[onOff ! SyntaxError => {intBad ← TRUE; CONTINUE}];
IF intBad THEN inlinePacketAllocate ← Bool[onOff];
}
ELSE inlinePacketAllocateCount ← IF inlinePacketAllocate THEN 1000 ELSE 0;
};
SetInlineRopeMarshal: PROCEDURE [onOff: Rope.ROPE] =
{ inlineRopeMarshal ← Bool[onOff] };
SetDynamicHeapNEWs: PROCEDURE [heap, mds: Rope.ROPE] =
{ maxHeapAllocs ← Int[heap]; maxMdsAllocs ← Int[mds] };
SetLineLength: PROCEDURE [length: Rope.ROPE] =
{ lineLength ← Int[length] };
SetDeclareSignals: PROCEDURE [onOff: Rope.ROPE] =
{ declareSignals ← Bool[onOff] };
SetWarnMDSAllocs: PROCEDURE [onOff: Rope.ROPE] =
{ warnMDSAllocs ← Bool[onOff] };
SetImportSingle: PROCEDURE [onOff: Rope.ROPE] =
{ importMultiple ← ~Bool[onOff] };
SetGeneratedClientModules: PROCEDURE [number: Rope.ROPE] = {
num: INT;
num ← Convert.IntFromRope[number ! Convert.Error => GOTO wrong];
IF num < 1 OR num > 9 THEN GOTO wrong;
noClientModulesOut ← num ;
EXITS wrong => {
out.PutRope["GeneratedClientModules must be in [0..9]"];
ERROR SyntaxError[];
};
};
TRUSTED{ out.PutF["Lupine version 1.2 of %g.\n\n",
[time[Loader.BCDBuildTime[]]] ] };
Wait[out];
ParseLine[IO.RIS[cmd.commandLine] !
SyntaxError => CONTINUE;
UNWIND => Finish[] ];
Finish[];
END;
Module Initialization.
Commander.Register[key: "Lupine",
proc: DoIt,
doc: "Produces stub modules for Cedar RPC; type \"Lupine Help\" for details"];
END.