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: BOOL ← FALSE, tokenKind: TokenKind, token: REF TEXT];
ParseWithoutKeyProc: TYPE = PROC[stream: IO.STREAM, buffer: REF TEXT] RETURNS [stop: BOOL ← FALSE, 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 TEXT ←
NIL, start:
INT ← 0, type: Type ← int, default: Value]
RETURNS [end:
INT ← 0, value: Value, ok:
BOOL ←
FALSE] = {
c: CHAR;
from: INT;
negative: BOOL ← FALSE;
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]]
];