/* Copyright (C) 1989, Digital Equipment Corporation */ /* All rights reserved. */ /* See the file COPYRIGHT for a full description. */ /* Last modified on Fri Nov 3 15:56:09 1989 by muller */ /* modified on Thu Nov 2 18:18:07 1989 by kalsow */ /* The routine AddLexLength is called by every lexical */ /* augment, in order to keep track of the number of */ /* characters that have been read. It simply adds */ /* the length of yytext to the accumulated count in lexposition , */ /* which is declared in pp.yacc . */ AddLexLength () { lexposition += yyleng; if (yyleng >= lexbufsize) { fprintf (stderr, "Lex buffer overflow in pretty-printer\n"); exit(-1); } } /* The routine BufferLexeme is used to copy a lexeme into */ /* the buffer declared in pp.yacc (which see) where it can */ /* be accessed by the parser actions. */ BufferLexeme () { int i; AddLexLength(); lexptr = lexbufsize - lexptr; yylval = lexptr; i = 0; while (yytext[i] != '\0') { lexbuf[lexptr + i] = yytext[i]; i = i + 1; }; lexbuf[lexptr+i] = '\0'; } /* The routine CapBufferLexeme is like BufferLexeme, but it capitalizes as it copies. */ CapBufferLexeme () { int i; AddLexLength(); lexptr = lexbufsize - lexptr; yylval = lexptr; i = 0; while (yytext[i] != '\0') { if (yytext[i] >= 'a' && yytext[i] <= 'z') { lexbuf[lexptr + i] = yytext[i] + 'A' - 'a'; } else { lexbuf[lexptr + i] = yytext[i]; i++; }} lexbuf[lexptr+i] = '\0'; } StripAndBufferLexeme () /* Like BufferLexeme, but strips everything until the */ /* first '('. Since this routine is only used for NLSLC and */ /* NLSLCNL, this amounts to stripping leading white space. */ { int i, j; AddLexLength(); lexptr = lexbufsize - lexptr; yylval = lexptr; i = 0; while (yytext[i] != '(') { i++; } j = 0; while (yytext[i] != '\0') { lexbuf[lexptr + j] = yytext[i]; j = j + 1; i = i + 1; }; lexbuf[lexptr+j] = '\0'; } %Start Prog Com /* Declare two states, Prog and Com. The lexical automaton is */ /* in state Prog outside comments and in state Com inside */ /* comments. (Since the pretty-printer must format comments, */ /* its lexical analyser must break them into words.) */ /* To handle comments, we will need to derive a regular */ /* expression for */ /* X = S* - S*abS* - S*bcS* */ /* where S is the alphabet of characters and a, b, and c are */ /* any three distinct characters in S. */ /* Let Xa be the subset of strings in X that end in a, Xb the */ /* subset of strings in X that end in b, and X0 = X - Xa - Xb. */ /* Then: */ /* (1) Xa = X0 a | Xa a | Xb a */ /* (2) Xb = X0 b | Xb b | Xb b */ /* (3) X0 = Xa (S-a-b) | Xb (S-a-b) | X0 (S-a-b) | "" */ /* From (1) and (2) we derive respectively: */ /* (4) Xa = ((X0 a) | Xb a) a* */ /* = X0 a+ | Xb a+ */ /* (5) Xb = ((X0 b) | Xa b) b* */ /* = X0 b+ | Xa b+ */ /* Substituting these into (3), we obtain */ /* (6) X0 = X0 a+ (S-a-b) */ /* | X0 b+ a+ (S-a-b) */ /* | X0 b+ (S-a-b) */ /* | X0 (S-a-b) */ /* | "" */ /* From (6) we immediately derive */ /* (7) X0 = ( a+(S-a-b) | b+a+(S-a-b) | */ /* b+(S-a-b-c) | (S-a-b) )* */ /* which is the required regular expression. */ /* Using (4) and (5) we derive */ /* (8) X = X0 ("" | a+ | b+ | b+a+ ) */ /* We use (7) and (8) in the derivation of */ /* CommentLine, a Lex expression for the body of */ /* a single-line comment, i.e., a comment body that */ /* fits on one line and does not have any comments */ /* nested within it. Thus S is any character but */ /* newline, a is "(", b is "*", and c is ")"; this */ /* prohibits "(*" or "*)" from occurring in the */ /* comment body. CLTemp is analogous to X0, and */ /* CommentLine is analogous to X = X0 | Xa | Xb. */ CLTemp ([(]+[^\n(*\001]|[*]+[(]+[^\n(*\001]|[*]+[^\n(*)\001]|[^\n(*\001])* CommentLine {CLTemp}(""|[(]+|[*]+[(]+|[*]+) /* Note that if the input stream were "***)", */ /* then CommentLine would match "***", leaving ")" */ /* in the input. This suggests that we have the */ /* problem of losing an endcomment marker. What */ /* we really want a CommentLine to be is something */ /* like (X0|Xa) | (Xb/[^)]), (mixing lex and real */ /* regular expressions). I.e., any CommentLine ending */ /* in a non-asterisk, or a CommentLine ending in an */ /* asterisk followed by something other than a right */ /* parenthesis. But we don't need to do this, because */ /* at each place CommentLine is used, the right context */ /* is specified and distinct from right parenthesis. */ /* But we aren't so lucky with CommentWord, which is */ /* like CommentLine except that blanks and tabs are */ /* prohibited as well as newline, and we have no */ /* guarantees about the right context. So these */ /* come in three flavors, two of which have restricted */ /* right contexts. */ /* NOTE: yyless was used instead of "/" in CommentWord2 */ /* because the "/" didn't work. */ CWTemp ([^ \t\n(*\001]|[(]+[^ \t\n*(\001]|[*]+[^ \t\n*()\001]|[*]+[(]+[^ \t\n*(\001])* CommentWord1 {CWTemp}(""|[(]+|[*]+[(]+|[*]+) CommentWord2 {CWTemp}[*]+[)] CommentWord3 {CWTemp}[*]*[(]+[*] %p 9000 %e 5000 %n 1000 %a 5000 %k 5000 %% "+" {BufferLexeme(); return(PLUS);} "-" {BufferLexeme(); return(MINUS);} "*" {BufferLexeme(); return(ASTERISK);} "/" {BufferLexeme(); return(SLASH);} ":=" {BufferLexeme(); return(ASSIGN);} "&" {BufferLexeme(); return(AMPERSAND);} "." {BufferLexeme(); return(DOT);} "," {BufferLexeme(); return(COMMA);} ";" {BufferLexeme(); return(SEMICOLON);} "(" {BufferLexeme(); return(LPAREN);} "[" {BufferLexeme(); return(LBRACKET);} "{" {BufferLexeme(); return(LBRACE);} "^" {BufferLexeme(); return(UPARROW);} "=" {BufferLexeme(); return(EQUAL);} "=>" {BufferLexeme(); return(RARROW);} "#" {BufferLexeme(); return(SHARP);} "<" {BufferLexeme(); return(LESS);} ">" {BufferLexeme(); return(GREATER);} "<=" {BufferLexeme(); return(LSEQUAL);} "<:" {BufferLexeme(); return(SUBTYPE);} ">=" {BufferLexeme(); return(GREQUAL);} ".." {BufferLexeme(); return(DOTDOT);} ":" {BufferLexeme(); return(COLON);} ")" {BufferLexeme(); return(RPAREN);} "]" {BufferLexeme(); return(RBRACKET);} "}" {BufferLexeme(); return(RBRACE);} "|" {BufferLexeme(); return(BAR);} [a-zA-Z@_][a-zA-Z0-9_]* {PTRKEYWORDENTRY tempp; if ((tempp=lookup(yytext))!=NULL){ CapBufferLexeme(); return(tempp->lexval);} else {BufferLexeme(); return(IDENT);}} "<*"[a-zA-Z0-9_]*"*>" {PTRKEYWORDENTRY tempp; if ((tempp=lookup(yytext))!=NULL){ CapBufferLexeme(); return(tempp->lexval);} else {BufferLexeme(); return(WORD);}} "<*ASSERT" {return(ASSERT);} "*>" {return(ENDPRAGMA);} [0-9]+(_[0-9A-Fa-f]+)? {BufferLexeme(); return(CARD_CONST);} [0-9]+"."[0-9]*([EeDd][-+]?[0-9]+)?/[^.] {BufferLexeme(); return(REAL_CONST);} ["]([^"\\\001\n]|["]["]|\\[^\001])*["] { BufferLexeme(); return(STR_CONST);} [']([^'\\\001\n]|['][']|\\[^\001])*['] { BufferLexeme(); return(STR_CONST);} "(*"{CommentLine}"*)"[\n\f][\n\f]* { BufferLexeme(); return(SLC); } [\n\f][ \t]*"(*"{CommentLine}"*)"[ \t]*/[\n\f] { StripAndBufferLexeme(); return(NLSLCNL); } [\n\f][ \t]*"(*"{CommentLine}"*)" { StripAndBufferLexeme(); return(NLSLC); } [\n\f][ \t]*[\n\f] {BufferLexeme(); return(BLANKLINE);} [ \t\n\f\015] {AddLexLength();} "(*" {BufferLexeme(); BEGIN Com; comdepth=1; return(BGNCOMMENT);} [\n\f][ \t]*"(*" {BufferLexeme(); BEGIN Com; comdepth = 1; return(NLBGNCOMMENT);} "(*" {BufferLexeme(); comdepth++; return(BGNCOMMENT);} "*)" {BufferLexeme(); comdepth--; if (comdepth==0) BEGIN Prog; return(ENDCOMMENT);} {CommentWord1} {BufferLexeme(); return(WORD);} {CommentWord2} {yyless(yyleng-2); BufferLexeme(); return(WORD);} {CommentWord3} {yyless(yyleng-2); BufferLexeme(); return(WORD);} [\n][\t|]{CommentLine}/[\n] {BufferLexeme(); return(TABLINE);} [\n\f](""|[ ][\t ]*)/[\n\f] {BufferLexeme(); return(BLANKLINE);} [ \t\n\f\015] {AddLexLength();} [ \t\n\f\r] {AddLexLength();} [\001] {BufferLexeme();return(ENDOFFILE);} [\002] {BufferLexeme();return(MODUNIT);} [\005] {BufferLexeme();return(DEFUNIT);} . {BufferLexeme(); return(BAD);} [\001] {BEGIN Prog; BufferLexeme(); return(ENDOFFILE);} [\002] {BEGIN Prog; BufferLexeme(); return(MODUNIT);} [\005] {BEGIN Prog; BufferLexeme(); return(DEFUNIT);} . {BufferLexeme(); BufferLexeme(); return(BAD);} . {yyless(0); BEGIN Prog;}