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 ];
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: BOOL ← FALSE;
freeServerArgs: BOOL ← TRUE;
inlineDispatcherStubs: BOOL ← TRUE;
inlineMarshal: BOOL ← TRUE;
inlinePacketAllocateCount: INT ← 1000;
inlineRopeMarshal: BOOL ← TRUE;
declareSignals: BOOL ← TRUE;
warnMDSAllocs: BOOL ← TRUE;
importMultiple: BOOL ← TRUE;
maxHeapAllocs: INT ← 50;
maxMdsAllocs: INT ← 50;
lineLength: INT ← 82;
noClientModulesOut: INT ← 1;
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.ROPE ← NIL;
DO key: Rope.
ROPE;
args: LIST OF Rope.ROPE ← NIL;
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: BOOLEAN ← FALSE;
translateOptions: LupineManager.Options;
HandleError: LupineManager.ErrorHandlerProc =
PROCEDURE [type: ErrorType, code: ErrorCode,
codeExplanation: String,
outputFileName: String←StringNIL,
outputFileCharPosition: LONG INTEGER,
problemCausingText: String←NIL ]
RETURNS [abortTranslation: BOOLEANLSE];
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:
BOOL ←
TRUE]
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:
BOOL ←
TRUE]
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: BOOL ← FALSE;
inlinePacketAllocate: BOOL ← FALSE;
inlinePacketAllocate ← Bool[onOff,
FALSE
! SyntaxError => {tryForInt ← TRUE; CONTINUE}];
IF tryForInt
THEN {
intBad: BOOL ← FALSE;
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;