GraphTextParser.mesa
Sweetsun Chen, August 10, 1985 4:23:25 pm PDT
OPEN Convert, Graph;
ROPE: TYPE = Rope.ROPE;
Value: TYPE = IO.Value;
STREAM: TYPE = IO.STREAM;
Error: SIGNAL[pos: INT, type: Atom, info: ROPE] = CODE;
-- Error types may be:
-- $UnknownKey: unrecognized keyword in a record.
ParseWithKeyProc: TYPE = PROC[stream: IO.STREAM, buffer, token: REF TEXT] RETURNS [stop: BOOLFALSE, tokenKind: TokenKind, token: REF TEXT];
ParseWithoutKeyProc: TYPE = PROC[stream: IO.STREAM, buffer: REF TEXT] RETURNS [stop: BOOLFALSE, tokenKind: TokenKind, token: REF TEXT];
typeRope: ARRAY [0..4) OF rope Value = ["number", "real number", "string of text enclosed by double quotes", "true or false"];
GetToken: PROC[stream: STREAM] RETURNS [tokenKind: TokenKind, token: REF TEXT] = {
buffer: REF TEXT = RefText.ObtainScratch[100];
error: IO.TokenError;
[tokenKind: tokenKind, token: token, error: error] ← IO.GetCedarToken[stream, buffer, TRUE];
IF error # none THEN Error[
pos: stream.GetPosition,
atom: $GetCedarTokenError,
info: SELECT error FROM
extendedChar => "extendedChar",
numericLiteral, charLiteral, stringLiteral, atomLiteral => "error in parsing indicated type",
singleChar => "first non-whitespace char is not legal as first char of token",
ENDCASE => "Impossible !? - #1."
];
}; -- GetToken
ValueFromNextToken: PROC[line: REF TEXTNIL, start: INT ← 0, type: Type ← int, default: Value] RETURNS [end: INT ← 0, value: Value, ok: BOOLFALSE] = {
c: CHAR;
from: INT;
negative: BOOLFALSE;
number: INT ← 0;
realNumber: REAL ← 0.0;
max: NAT ← line.length;
position index can not be >= max.
-- skip to the first non-blank char to get the "from" index
from ← end ← start;
WHILE from < max DO
SELECT line[from] FROM
<= SP, 140C, DEL => from ← from + 1;
ENDCASE => EXIT;
ENDLOOP;
IF (end ← from) >= max THEN RETURN[]; -- not ok
-- now lets get the "end" index, by skipping alphanumeric
SELECT type FROM
int => {
c ← line[end];
IF c = '+ OR c = '- THEN {
IF c = '- THEN negative ← TRUE;
IF (end ← end + 1) = max THEN RETURN[]; -- just the sign
};
WHILE (c ← line[end]) IN ['0..'9] DO
number ← number*10 + (c - '0);
IF (end ← end + 1) = max THEN EXIT;
ENDLOOP;
RETURN[end, IF negative THEN -number ELSE number, TRUE];
}; -- int
real => {
c ← line[end];
IF c = '+ OR c = '- THEN {
IF c = '- THEN negative ← TRUE;
IF (end ← end + 1) = max THEN RETURN[]; -- just the sign
};
WHILE (c ← line[end]) IN ['0..'9] DO
realNumber ← realNumber*10.0 + Real.Float[c - '0];
IF (end ← end + 1) = max THEN GOTO done;
ENDLOOP;
IF c = '. THEN {
end ← end + 1;
IF end = max THEN GOTO done;
WHILE c ← text.Fetch[end] IN ['0..'9] DO
end ← end + 1;
IF end = max THEN GOTO done;
ENDLOOP;
IF c = 'E OR c = 'e THEN {
end ← end + 1;
IF end = max THEN GOTO done;
WHILE c ← text.Fetch[end] IN ['0..'9] DO
end ← end + 1;
IF end = max THEN GOTO done;
ENDLOOP;
};
};
EXITS
done =>
IF type = real THEN {
IF negative THEN realNumber ← -realNumber;
RETURN[end, realNumber, TRUE];
}
ELSE {
IF negative THEN number ← -number;
RETURN[end, number, TRUE];
};
};
real => {
c: CHAR;
WHILE (c ← text.Fetch[end]) IN ['0..'9] DO
end ← end + 1;
IF end = max THEN EXIT;
ENDLOOP;
SELECT c FROM
'. => end ← end + 1;
'e, 'E
token ← text.Substr[start, end-start];
}; -- GetTokenFromRope
GetValues: PROC[s: IO.STREAM, args, defaults: RopeArray, types: TypeArray, numArgs: INT]
RETURNS [values: Values] = {
pos: INT ← s.GetPosition;
lineRope: ROPE ← ReadUpTo[s, '] !
=> Error[PutFR["Can't find the closing square braket ']' starting from %g.", int[pos]]];
lineText: REF TEXT = FromRefText[rope];
len: NAT ← lineText.length;
start, end: NAT ← 0;
colon: INTEGER ← -1;
FOR i: NAT IN [0..lineText.length) DO
IF lineText[i] = ': THEN {colon ← i; EXIT};
ENDLOOP;
IF colon < 0 THEN { -- no keywords
FOR i: INT IN [0..numArgs) DO
IF start >= len THEN values[i] ← defaults[i]
ELSE [end, values[i], ok] ← ValueFromNextToken[lineText, start, types[i], defaults[i]];
IF NOT ok THEN Error[
PutFR[
"Had difficulty at [%g], parsing
%g ....
to get the value of argument # %g,
which I think should be a %g with default %g.",
int[pos + start],
rope[lineRope.Substr[0, MIN[len, 20]]],
int[i+1],
typeRope[i], defaults[i]
];
];
start ← end + 1;
ENDLOOP;
}
ELSE {
keyword: rope Value;
values ← defaults;
start ← end ← 0;
UNTIL start >= len DO
[end, keyword, ok] ← ValueFromNextToken[line, start, rope, len];
IF NOT ok THEN Error[
"Had difficulty at [%g] parsing\n %g ....\n to get a keyword.",
int[pos + start],
rope[rope.Substr[0, MIN[len, 20]]],
];
FOR i: INT IN [0..numArgs) DO
IF keyword.Equal[args[i], FALSE] THEN {
start ← end + 1;
[end, values[i]] ← GetTokenFromRope[line, start, types[i], len];
IF values[i] = NIL THEN values[i] ← defaults[i];
end ← start + 1;
EXIT;
};
REPEATS
FINISHED => Error["Illegal argument."];
ENDLOOP;
ENDLOOP;
};
}; -- GetValues
Parse: PROC[stream: IO.STREAM, var: REF ANY] = {
assume stream, var, and key are not nil.
WITH var SELECT FROM
t: Text => t← ParseText
ParseRGB: PROC[stream: IO.STREAM] RETURNS [ImagerColor.RGB] = {
ParseColors: PROC[stream: IO.STREAM, graph: GRAPH] RETURNS [tokenKind: TokenKind, token: REF TEXT] = {
tokenKind: IO.TokenKind; token: REF TEXT;
buffer: REF TEXT = RefText.ObtainScratch[100];
error: IO.TokenError;
ParseWithKey: ParseWithKeyProc = {
UNTIL stop DO
rgb: {r, g, b};
c: CHAR;
SELECT token[0] FROM
'R, 'r => rgb ← r, 'G, 'g => rgb ← g, 'B, 'b => rgb ← b,
ENDCASE => Error[
pos: s.GetPosition[],
atom: $UnknownKey
info: "`r', `g', or `b' are expected."
];
c ← IO.GetCharLiteral[stream];
[tokenKind: tokenKind, token: token] ← GetToken[stream];
SELECT tokenKind FROM
tokenID => [tokenKind, token] ← ParseWithKey[stream, token];
Parse[stream, graph,
GetToken[s]
hasKeyword ← ParseIndex
args: ARRAY [0..4) OF ROPE = ["index", "r", "g", "b"];
defaults: ARRAY [0..4) OF Value = [int[0], real[0.0], real[0.0], real[0.0]];
types: ARRAY [0..4) OF Type = [int, real, real, real];
values: ARRAY [0..4) OF Value ← GetValues[s, args, defaults, types, 4 !
=> {
msg ← IO.PutFR["Had difficulty processing 'Color' command at pos = [%g].",
IO.int[s.GetPosition[]]];
CONTINUE;
}
];
graph.color[values[1].value] ←
IF msg = NIL THEN SetColor[
viewer: viewer,
index: IntFromRope[values[0]],
r: RealFromRope[values[1]],
g: RealFromRope[values[2]],
b: RealFromRope[values[3]]
];
}; -- Color