/**************************************************************************** ** *FSyntaxErrorOrWarning(<msg>)......raiseasyntaxerrororwarning ** **Helperfunctionusedby'SyntaxError'and'SyntaxWarning'. **
*/ staticvoid SyntaxErrorOrWarning(ScannerState * s, constChar * msg,
UInt error, Int tokenoffset)
{
GAP_ASSERT(tokenoffset >= 0 && tokenoffset <= 2); // do not print a message if we found one already on the current line if (s->input->lastErrorLine != s->input->number) {
// print the message ... if (error)
Pr("Syntax error: %s", (Int)msg, 0); else
Pr("Syntax warning: %s", (Int)msg, 0);
// ... and the filename + line, unless it is '*stdin*'
Obj name = GetCachedFilename(GetInputFilenameID(s->input)); if (!streq("*stdin*", CONST_CSTR_STRING(name)))
Pr(" in %g:%d", (Int)name, GetInputLineNumber(s->input));
Pr("\n", 0, 0);
// print the current line constchar * line = GetInputLineBuffer(s->input); const UInt len = strlen(line); if (len > 0 && line[len-1] != '\n')
Pr("%s\n", (Int)line, 0); else
Pr("%s", (Int)line, 0);
// print a '^' pointing to the current position Int startPos = s->SymbolStartPos[tokenoffset]; Int pos; if (tokenoffset == 0)
pos = GetInputLinePosition(s->input); else
pos = s->SymbolStartPos[tokenoffset - 1];
// if 's->Symbol' is the expected symbol match it away if (symbol == s->Symbol) {
s->Symbol = NextSymbol(s);
}
// else generate an error message and skip to a symbol in <skipto> else {
gap_strlcpy( errmsg, msg, sizeof(errmsg) );
gap_strlcat( errmsg, " expected", sizeof(errmsg) );
SyntaxError(s, errmsg); while (!IS_IN(s->Symbol, skipto))
s->Symbol = NextSymbol(s);
}
}
/**************************************************************************** ** *FGetIdent().............getanidentifierorkeyword,local ** **'GetIdent'readsanidentifierfromthecurrentinputfileintothe **variable's->Value'andsets'Symbol'to'S_IDENT'.Thefirst **characteroftheidentifieristhecurrentcharacterpointedtoby'In'. **Ifthecharactersmakeupakeyword'GetIdent'willset'Symbol'tothe **correspondingvalue.Theparserwillignore's->Value'inthiscase. ** **Anidentifierconsistsofaletterfollowedbymoreletters,digitsand **underscores'_'.Anidentifieristerminatedbythefirstcharacternot **inthisclass.Thebackslash'\'canbeusedtoincludespecial **characterslike'('inidentifiers.Forexample'G\(2\,5\)'isan **identifiernotacalltoafunction'G'. ** **Thesizeof's->Value'limitsthenumberofsignificantcharactersin **anidentifier.Ifanidentifierhasmorecharacters'GetIdent'truncates **itandsignalasyntaxerror. ** **Afterreadingtheidentifier'GetIdent'looksatthefirstandthelast **characterof's->Value'toseeifitcouldpossiblybeakeyword.For **example'test'couldnotbeakeywordbecausethereisnokeyword **startingandendingwitha't'.Afterthattesteither'GetIdent'knows **that's->Value'isnotakeyword,orthereisauniquepossible **keywordthatcouldmatch,becausenotwokeywordshaveidenticalfirst **andlastcharacters.Forexampleif's->Value'startswith'f'and **endswith'n'theonlypossiblekeywordis'function'.Thusinthiscase **'GetIdent'candecidewithonestringcomparisonif's->Value'holds **akeywordornot.
*/ static UInt GetIdent(ScannerState * s, Int i, Char c)
{ // initially it could be a keyword Int isQuoted = 0;
// read all characters into 's->Value' for (; IsIdent(c) || c == '\\'; i++) {
// handle escape sequences if (c == '\\') {
c = GET_NEXT_CHAR(); switch(c) { case'n': c = '\n'; break; case't': c = '\t'; break; case'r': c = '\r'; break; case'b': c = '\b'; break; default:
isQuoted = 1;
}
}
/// put char into 's->Value' but only if there is room if (i < MAX_VALUE_LEN - 1)
s->Value[i] = c;
// read the next character
c = GET_NEXT_CHAR();
}
// reject overlong identifiers if (i > MAX_VALUE_LEN - 1) {
SyntaxError(
s, "Identifiers in GAP must consist of at most 1023 characters.");
i = MAX_VALUE_LEN - 1;
}
// terminate the identifier
s->Value[i] = '\0';
// if it is quoted then it is not a keyword if (isQuoted) return S_IDENT;
static UInt GetNumber(ScannerState * s, Int readDecimalPoint, Char c)
{
UInt symbol = S_ILLEGAL;
UInt i = 0; BOOL seenADigit = FALSE;
s->ValueObj = 0;
if (readDecimalPoint) {
s->Value[i++] = '.';
} else { // read initial sequence of digits into 'Value' while (IsDigit(c)) {
i = AddCharToValue(s, i, c);
seenADigit = TRUE;
c = GET_NEXT_CHAR();
}
// maybe we saw an identifier character and realised that this is an // identifier we are reading if (IsIdent(c) || c == '\\') { // if necessary, copy back from s->ValueObj to s->Value if (s->ValueObj) {
i = GET_LEN_STRING(s->ValueObj);
GAP_ASSERT(i >= MAX_VALUE_LEN - 1);
memcpy(s->Value, CONST_CSTR_STRING(s->ValueObj),
MAX_VALUE_LEN);
s->ValueObj = 0;
} // this looks like an identifier, scan the rest of it return GetIdent(s, i, c);
}
// Or maybe we saw a '.' which could indicate one of three things: // - a float literal: 12.345 // - S_DOT, i.e., '.' used to access a record entry: r.12.345 // - S_DDOT, i.e., '..' in a range expression: [12..345] if (c == '.') {
GAP_ASSERT(i < MAX_VALUE_LEN - 1);
// If the symbol before this integer was S_DOT then we must be in // a nested record element expression, so don't look for a float. // This is a bit fragile if (s->Symbol == S_DOT || s->Symbol == S_BDOT) {
symbol = S_INT; goto finish;
}
// peek ahead to decide if we are looking at a range expression if (PEEK_NEXT_CHAR(s->input) == '.') { // we are looking at '..' and are probably inside a range // expression
symbol = S_INT; goto finish;
}
// Now the '.' must be part of our number; store it and move on
i = AddCharToValue(s, i, '.');
c = GET_NEXT_CHAR();
} else { // Anything else we see tells us that the token is done
symbol = S_INT; goto finish;
}
}
// When we get here we have read possibly some digits, a . and possibly // some more digits, but not an e,E,d,D,q or Q // In any case, from now on, we know we are dealing with a float literal
symbol = S_FLOAT;
// read digits while (IsDigit(c)) {
i = AddCharToValue(s, i, c);
seenADigit = TRUE;
c = GET_NEXT_CHAR();
} if (!seenADigit)
SyntaxError(s, "Badly formed number: need a digit before or after the " "decimal point"); if (c == '\\')
SyntaxError(s, "Badly formed number");
// If the next thing is the start of the exponential notation, read it // now. if (c == 'e' || c == 'E' || c == 'd' || c == 'D' || c == 'q' ||
c == 'Q') {
i = AddCharToValue(s, i, c);
c = GET_NEXT_CHAR(); if (c == '+' || c == '-') {
i = AddCharToValue(s, i, c);
c = GET_NEXT_CHAR();
}
// Here we are into the unsigned exponent of a number in scientific // notation, so we just read digits if (!IsDigit(c))
SyntaxError(s, "Badly formed number: need at least one digit in " "the exponent"); while (IsDigit(c)) {
i = AddCharToValue(s, i, c);
c = GET_NEXT_CHAR();
}
}
// Allow one letter at the end of the number, which is a conversion // marker; e.g. an `i` as in C99, to indicate an imaginary value. if (IsAlpha(c)) {
i = AddCharToValue(s, i, c);
c = GET_NEXT_CHAR();
}
// independently of that, we allow an _ signalling immediate or "eager" // conversion if (c == '_') {
i = AddCharToValue(s, i, c);
c = GET_NEXT_CHAR(); // After which there may be one character signifying the // conversion styles if (IsAlpha(c)) {
i = AddCharToValue(s, i, c);
c = GET_NEXT_CHAR();
}
}
// Now if the next character is an identifier symbol then we have an error if (IsIdent(c)) {
SyntaxError(s, "Badly formed number");
}
finish:
i = AddCharToValue(s, i, '\0'); if (s->ValueObj) { // flush buffer
AppendBufToString(s->ValueObj, s->Value, i - 1);
} return symbol;
}
if ( c == 'n' ) result = '\n'; elseif ( c == 't' ) result = '\t'; elseif ( c == 'r' ) result = '\r'; elseif ( c == 'b' ) result = '\b'; elseif ( c == '>' ) result = '\01'; elseif ( c == '<' ) result = '\02'; elseif ( c == 'c' ) result = '\03'; elseif ( c == '"' ) result = '"'; elseif ( c == '\\' ) result = '\\'; elseif ( c == '\'' ) result = '\''; elseif ( c == '0' ) { // from here we can either read a hex-escape or three digit octal numbers
c = GET_NEXT_CHAR(); if (c == 'x') {
result = 16 * CharHexDigit(s);
result += CharHexDigit(s);
} elseif (c >= '0' && c <= '7') {
result += GetOctalDigits(s, c);
} else {
SyntaxError(s, "Expecting hexadecimal escape, or two more octal digits");
}
} elseif ( c >= '1' && c <= '7' ) { // escaped three digit octal numbers are allowed in input
result = 64 * (c - '0');
c = GET_NEXT_CHAR();
result += GetOctalDigits(s, c);
} else { // Following discussions on pull-request #612, this warning is currently // disabled for backwards compatibility; some code relies on this behaviour // and tests break with the warning enabled #if0 if (IsAlpha(c))
SyntaxWarning(s, "Alphabet letter after \\"); #endif
result = c;
} return result;
}
// print only a partial prompt while reading a triple string
SetPrompt("> ");
while (c != '\377') { // only thing to check for is a triple quote if (c == '"') {
c = GET_NEXT_CHAR(); if (c == '"') {
c = GET_NEXT_CHAR(); if (c == '"') { break;
}
i = AddCharToBuf(&string, buf, sizeof(buf), i, '"');
}
i = AddCharToBuf(&string, buf, sizeof(buf), i, '"');
}
i = AddCharToBuf(&string, buf, sizeof(buf), i, c);
// read the next character
c = GET_NEXT_CHAR();
}
// append any remaining data to s->ValueObj
s->ValueObj = AppendBufToString(string, buf, i);
if (c == '\377') {
FlushRestOfInputLine(s->input);
SyntaxError(s, "String must end with \"\"\" before end of file");
}
if (c == '"') {
c = GET_NEXT_CHAR(); if (c == '"') {
isTripleQuoted = 1;
c = GET_NEXT_CHAR();
} else { // we read two '"' followed by something else, so this was // just an empty string!
s->ValueObj = NEW_STRING(0); return;
}
}
c = isTripleQuoted ? GetTripStr(s, c) : GetStr(s, c);
// skip trailing '"' if (c == '"')
c = GET_NEXT_CHAR();
}
// handle escape equences if ( c == '\n' ) {
SyntaxError(s, "Character literal must not include <newline>");
} else { if ( c == '\\' ) {
s->Value[0] = GetEscapedChar(s);
} else { // put normal chars into 's->Value'
s->Value[0] = c;
}
// read the next character
c = GET_NEXT_CHAR();
// check for terminating single quote, and skip if ( c == '\'' ) {
c = GET_NEXT_CHAR();
} else {
SyntaxError(s, "Missing single quote in character constant");
}
}
}
/**************************************************************************** ** *FNextSymbol().................getthenextsymbol,local ** **'NextSymbol'readsthenextsymbolfromtheinput,storingitinthe **variable's->Symbol'.If's->Symbol'is'S_IDENT','S_INT', **'S_FLOAT'or'S_STRING'thevalueofthesymbolisstoredin **'s->Value'or's->ValueObj'.'NextSymbol'firstskipsall **<space>,<tab>and<newline>charactersandcomments. ** **Afterreadingasymbolthecurrentcharacteristhefirstcharacter **beyondthatsymbol.
*/ static UInt NextSymbol(ScannerState * s)
{ // Record end of previous symbol's position
StoreSymbolPosition(s);
Char c = PEEK_CURR_CHAR(s->input);
// skip over <spaces>, <tabs>, <newlines> and comments while (c == ' ' || c == '\t' || c== '\n' || c== '\r' || c == '\f' || c=='#') { if (c == '#') {
c = GET_NEXT_CHAR_NO_LC(s->input); if (c == '%') { // we have encountered a pragma
GetPragma(s, c); return S_PRAGMA;
}
SKIP_TO_END_OF_LINE(s->input);
}
c = GET_NEXT_CHAR();
}
// Record start of this symbol's position
StoreSymbolPosition(s);
// switch according to the character if (IsAlpha(c)) { return GetIdent(s, 0, c);
}
UInt symbol;
switch (c) { case'.': symbol = S_DOT; c = GET_NEXT_CHAR(); if (c == '.') { symbol = S_DOTDOT; c = GET_NEXT_CHAR(); if (c == '.') { symbol = S_DOTDOTDOT; c = GET_NEXT_CHAR(); }
} break;
case'!': symbol = S_ILLEGAL; c = GET_NEXT_CHAR(); if (c == '.') { symbol = S_BDOT; GET_NEXT_CHAR(); break; } if (c == '[') { symbol = S_BLBRACK; GET_NEXT_CHAR(); break; } break; case'[': symbol = S_LBRACK; GET_NEXT_CHAR(); break; case']': symbol = S_RBRACK; GET_NEXT_CHAR(); break; case'{': symbol = S_LBRACE; GET_NEXT_CHAR(); break; case'}': symbol = S_RBRACE; GET_NEXT_CHAR(); break; case'(': symbol = S_LPAREN; GET_NEXT_CHAR(); break; case')': symbol = S_RPAREN; GET_NEXT_CHAR(); break; case',': symbol = S_COMMA; GET_NEXT_CHAR(); break;
case':': symbol = S_COLON; c = GET_NEXT_CHAR(); if (c == '=') { symbol = S_ASSIGN; GET_NEXT_CHAR(); break; } break;
case';': symbol = S_SEMICOLON; c = GET_NEXT_CHAR(); if (c == ';') { symbol = S_DUALSEMICOLON; GET_NEXT_CHAR(); break; } break;
case'=': symbol = S_EQ; GET_NEXT_CHAR(); break; case'<': symbol = S_LT; c = GET_NEXT_CHAR(); if (c == '=') { symbol = S_LE; GET_NEXT_CHAR(); break; } if (c == '>') { symbol = S_NE; GET_NEXT_CHAR(); break; } break; case'>': symbol = S_GT; c = GET_NEXT_CHAR(); if (c == '=') { symbol = S_GE; GET_NEXT_CHAR(); break; } break;
case'+': symbol = S_PLUS; GET_NEXT_CHAR(); break; case'-': symbol = S_MINUS; c = GET_NEXT_CHAR(); if (c == '>') { symbol = S_MAPTO; GET_NEXT_CHAR(); break; } break; case'*': symbol = S_MULT; GET_NEXT_CHAR(); break; case'/': symbol = S_DIV; GET_NEXT_CHAR(); break; case'^': symbol = S_POW; GET_NEXT_CHAR(); break;
case'~': symbol = S_TILDE; GET_NEXT_CHAR(); break; case'?': symbol = S_HELP; GetHelp(s); break; case'"': symbol = S_STRING; GetString(s); break; case'\'': symbol = S_CHAR; GetChar(s); break; case'\\': return GetIdent(s, 0, c); case'_': return GetIdent(s, 0, c); case'@': return GetIdent(s, 0, c);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.