2024-10-10
This commit is contained in:
338
core/sim/sim_3_01/m2lang.l
Normal file
338
core/sim/sim_3_01/m2lang.l
Normal file
@@ -0,0 +1,338 @@
|
||||
%{
|
||||
/* This file is part of the software similarity tester SIM.
|
||||
Written by Dick Grune, Vrije Universiteit, Amsterdam.
|
||||
$Id: m2lang.l,v 2.21 2017-03-19 09:23:19 dick Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
Modula-2 language front end for the similarity tester.
|
||||
Author: Dick Grune <dick@cs.vu.nl>
|
||||
*/
|
||||
|
||||
#include "options.h"
|
||||
#include "token.h"
|
||||
#include "language.h"
|
||||
#include "algollike.h"
|
||||
#include "idf.h"
|
||||
#include "lex.h"
|
||||
#include "lang.h"
|
||||
|
||||
/* General language front end data */
|
||||
Token lex_token;
|
||||
size_t lex_nl_cnt;
|
||||
size_t lex_tk_cnt;
|
||||
size_t lex_non_ascii_cnt;
|
||||
|
||||
/* Language-dependent data */
|
||||
|
||||
/* Most Modula-2 programs start with a number of IMPORTs that look
|
||||
very similar from program to program. These are skipped by ignoring
|
||||
the reserved words IMPLEMENTATION, DEFINITION, MODULE, IMPORT
|
||||
and FROM, having a flag skip_imports, and start reacting only
|
||||
at the first non-ignored reserved word.
|
||||
|
||||
Also, the nesting comments require a state variable.
|
||||
*/
|
||||
|
||||
/* Additional state variables, set in yystart() */
|
||||
static int skip_imports;
|
||||
static int comment_level;
|
||||
|
||||
/* Data for module idf */
|
||||
|
||||
static const struct idf reserved[] = {
|
||||
{"AND", NORM('&')},
|
||||
{"ARRAY", NORM('A')},
|
||||
{"BEGIN", NORM('{')},
|
||||
{"BY", NORM('B')},
|
||||
{"CASE", NORM('c')},
|
||||
{"CONST", NORM('C')},
|
||||
{"DEFINITION", No_Token},
|
||||
{"DIV", NORM('/')},
|
||||
{"DO", NORM('D')},
|
||||
{"ELSE", NORM('e')},
|
||||
{"ELSIF", NORM('e')},
|
||||
{"END", NORM('}')},
|
||||
{"EXIT", NORM('E')},
|
||||
{"EXPORT", CTRL('E')},
|
||||
{"FOR", NORM('F')},
|
||||
{"FROM", No_Token},
|
||||
{"IF", NORM('i')},
|
||||
{"IMPLEMENTATION", No_Token},
|
||||
{"IMPORT", No_Token},
|
||||
{"IN", NORM('I')},
|
||||
{"LOOP", NORM('l')},
|
||||
{"MOD", NORM('%')},
|
||||
{"MODULE", No_Token},
|
||||
{"NOT", NORM('~')},
|
||||
{"OF", No_Token},
|
||||
{"OR", NORM('O')},
|
||||
{"POINTER", NORM('p')},
|
||||
{"PROCEDURE", NORM('P')},
|
||||
{"QUALIFIED", NORM('q')},
|
||||
{"RECORD", NORM('r')},
|
||||
{"REPEAT", NORM('R')},
|
||||
{"RETURN", CTRL('r')},
|
||||
{"SET", NORM('s')},
|
||||
{"THEN", No_Token},
|
||||
{"TO", NORM('t')},
|
||||
{"TYPE", NORM('T')},
|
||||
{"UNTIL", NORM('u')},
|
||||
{"VAR", NORM('v')},
|
||||
{"WHILE", NORM('w')},
|
||||
{"WITH", NORM('W')},
|
||||
};
|
||||
|
||||
static const struct idf standard[] = {
|
||||
{"ABS", META('a')},
|
||||
{"ADDRESS", META('A')},
|
||||
{"ALLOCATE", MTCT('A')},
|
||||
{"BITSET", META('b')},
|
||||
{"BOOLEAN", META('B')},
|
||||
{"CAP", META('c')},
|
||||
{"CARDINAL", META('C')},
|
||||
{"CHAR", MTCT('C')},
|
||||
{"CHR", META('x')},
|
||||
{"DEALLOCATE", META('d')},
|
||||
{"DEC", META('D')},
|
||||
{"EXCL", META('e')},
|
||||
{"FALSE", META('f')},
|
||||
{"FLOAT", META('F')},
|
||||
{"HALT", META('h')},
|
||||
{"HIGH", META('H')},
|
||||
{"INC", META('i')},
|
||||
{"INCL", META('I')},
|
||||
{"INTEGER", MTCT('I')},
|
||||
{"LONGCARD", META('L')},
|
||||
{"LONGINT", META('L')},
|
||||
{"LONGREAL", META('L')},
|
||||
{"MAX", META('m')},
|
||||
{"MIN", META('M')},
|
||||
{"NEWPROCESS", META('n')},
|
||||
{"NIL", META('N')},
|
||||
{"ODD", META('o')},
|
||||
{"ORD", META('O')},
|
||||
{"PROC", META('p')},
|
||||
{"REAL", META('r')},
|
||||
{"SIZE", META('s')},
|
||||
{"SYSTEM", META('S')},
|
||||
{"TRANSFER", META('t')},
|
||||
{"TRUE", META('T')},
|
||||
{"TRUNC", MTCT('T')},
|
||||
{"VAL", META('v')},
|
||||
{"WORD", META('w')}
|
||||
};
|
||||
|
||||
/* Special treatment of identifiers */
|
||||
|
||||
static Token
|
||||
idf2token(int hashing) {
|
||||
Token tk;
|
||||
|
||||
/* the token can be on two lists, reserved and standard */
|
||||
tk = idf_in_list(yytext, reserved, sizeof reserved, IDF);
|
||||
|
||||
/* is it one of the keywords to be ignored? */
|
||||
if (Token_EQ(tk, No_Token)) return tk;
|
||||
|
||||
/* The statement below is a significant comment
|
||||
on the value of state variables.
|
||||
*/
|
||||
if (!Token_EQ(tk, IDF)) {
|
||||
/* reserved word, stop the skipping */
|
||||
skip_imports = 0;
|
||||
}
|
||||
else {
|
||||
/* it is an identifier but not a reserved word */
|
||||
if (skip_imports) {
|
||||
/* skip it */
|
||||
tk = 0;
|
||||
}
|
||||
else {
|
||||
/* look further */
|
||||
tk = idf_in_list(yytext, standard, sizeof standard, IDF);
|
||||
if (Token_EQ(tk, IDF) && hashing) {
|
||||
/* return a one-Token hash code */
|
||||
tk = idf_hashed(yytext);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tk;
|
||||
}
|
||||
|
||||
/* Token sets for module algollike */
|
||||
const Token Non_Finals[] = {
|
||||
IDF, /* identifier */
|
||||
NORM('{'), /* also BEGIN */
|
||||
NORM('('),
|
||||
NORM('['),
|
||||
NORM('A'), /* ARRAY */
|
||||
NORM('c'), /* CASE */
|
||||
NORM('C'), /* CONST */
|
||||
NORM('E'), /* EXIT */
|
||||
NORM('F'), /* FOR */
|
||||
NORM('i'), /* IF */
|
||||
NORM('l'), /* LOOP */
|
||||
NORM('p'), /* POINTER */
|
||||
NORM('P'), /* PROCEDURE */
|
||||
NORM('r'), /* RECORD */
|
||||
NORM('R'), /* REPEAT */
|
||||
CTRL('R'), /* RETURN */
|
||||
NORM('s'), /* SET */
|
||||
NORM('T'), /* TYPE */
|
||||
NORM('v'), /* VAR */
|
||||
NORM('w'), /* WHILE */
|
||||
NORM('W'), /* WITH */
|
||||
No_Token
|
||||
};
|
||||
const Token Non_Initials[] = {
|
||||
NORM('}'),
|
||||
NORM(')'),
|
||||
NORM(']'),
|
||||
NORM(';'),
|
||||
No_Token
|
||||
};
|
||||
const Token Openers[] = {
|
||||
NORM('{'),
|
||||
NORM('('),
|
||||
NORM('['),
|
||||
No_Token
|
||||
};
|
||||
const Token Closers[] = {
|
||||
NORM('}'),
|
||||
NORM(')'),
|
||||
NORM(']'),
|
||||
No_Token
|
||||
};
|
||||
|
||||
/* Language-dependent code */
|
||||
|
||||
const char *Subject = "Modula-2 programs";
|
||||
|
||||
void
|
||||
Init_Language(void) {
|
||||
Init_Algol_Language(Non_Finals, Non_Initials, Openers, Closers);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
May_Be_Start_Of_Run(Token ch) {
|
||||
return May_Be_Start_Of_Algol_Run(ch);
|
||||
}
|
||||
|
||||
size_t
|
||||
Best_Run_Size(const Token *str, size_t size) {
|
||||
return Best_Algol_Run_Size(str, size);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%option noyywrap
|
||||
|
||||
%Start Comment
|
||||
|
||||
Layout ([ \t\r\f])
|
||||
ASCII95 ([\040-\176])
|
||||
|
||||
AnyQuoted (\\.)
|
||||
QuStrChar ([^\"\n\\]|{AnyQuoted})
|
||||
ApoStrChar ([^\'\n\\]|{AnyQuoted})
|
||||
|
||||
StartComment ("(*")
|
||||
EndComment ("*)")
|
||||
SafeComChar ([^*\n])
|
||||
UnsafeComChar ("*")
|
||||
|
||||
Digit ([0-9a-fA-F])
|
||||
Idf ([A-Za-z][A-Za-z0-9_]*)
|
||||
|
||||
%%
|
||||
|
||||
{StartComment} { /* See clang.l */
|
||||
/* Lex itself is incapable of handling Modula-2's
|
||||
nested comments. So let's help it a bit.
|
||||
*/
|
||||
if (comment_level == 0) {
|
||||
BEGIN Comment;
|
||||
}
|
||||
comment_level++;
|
||||
}
|
||||
|
||||
<Comment>{SafeComChar}+ { /* safe comment chunk */
|
||||
}
|
||||
|
||||
<Comment>{UnsafeComChar} { /* unsafe char, read one by one */
|
||||
}
|
||||
|
||||
<Comment>"\n" { /* to break up long comments */
|
||||
return_eol();
|
||||
}
|
||||
|
||||
<Comment>{EndComment} { /* end-of-comment */
|
||||
comment_level--;
|
||||
if (comment_level == 0) {
|
||||
BEGIN INITIAL;
|
||||
}
|
||||
}
|
||||
|
||||
\"{QuStrChar}*\" { /* quoted strings */
|
||||
return_ch('"');
|
||||
}
|
||||
|
||||
\'{ApoStrChar}*\' { /* apostrophed strings */
|
||||
return_ch('"');
|
||||
}
|
||||
|
||||
{Digit}+("B"|"C"|"H")? { /* numeral, passed as an identifier */
|
||||
return_tk(IDF);
|
||||
}
|
||||
|
||||
"END"{Layout}*{Idf} { /* ignore identifier after END */
|
||||
Token tk =
|
||||
idf_in_list("END", reserved, sizeof reserved, No_Token);
|
||||
if (!Token_EQ(tk, No_Token)) return_tk(tk);
|
||||
}
|
||||
|
||||
{Idf}/"(" { /* identifier in front of ( */
|
||||
Token tk = idf2token(is_set_option('F')/* hashing option */);
|
||||
if (!Token_EQ(tk, No_Token)) return_tk(tk);
|
||||
}
|
||||
|
||||
{Idf} { /* identifier */
|
||||
Token tk = idf2token(0 /* no hashing */);
|
||||
if (!Token_EQ(tk, No_Token)) return_tk(tk);
|
||||
}
|
||||
|
||||
"<>" { /* <>, special equivalence */
|
||||
return_ch('#');
|
||||
}
|
||||
|
||||
\; { /* semicolon, conditionally ignored */
|
||||
if (is_set_option('f')) return_ch(yytext[0]);
|
||||
}
|
||||
|
||||
\n { /* count newlines */
|
||||
return_eol();
|
||||
}
|
||||
|
||||
{Layout} { /* ignore layout */
|
||||
}
|
||||
|
||||
{ASCII95} { /* copy other text */
|
||||
if (!skip_imports) return_ch(yytext[0]);
|
||||
}
|
||||
|
||||
. { /* count non-ASCII chars */
|
||||
lex_non_ascii_cnt++;
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
/* More language-dependent code */
|
||||
|
||||
void
|
||||
yystart(void) {
|
||||
skip_imports = 1;
|
||||
comment_level = 0;
|
||||
BEGIN INITIAL;
|
||||
}
|
||||
Reference in New Issue
Block a user