-
Botond Baranyi authored
Signed-off-by:
Botond Baranyi <botond.baranyi@ericsson.com>
Botond Baranyi authoredSigned-off-by:
Botond Baranyi <botond.baranyi@ericsson.com>
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
compiler.l 33.56 KiB
/******************************************************************************
* Copyright (c) 2000-2021 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* Baji, Laszlo
* Balasko, Jeno
* Baranyi, Botond
* Cserveni, Akos
* Delic, Adam
* Feher, Csaba
* Forstner, Matyas
* Kovacs, Ferenc
* Kremer, Peter
* Raduly, Csaba
* Szabados, Kristof
* Szabo, Bence Janos
* Szabo, Janos Zoltan – initial implementation
* Zalanyi, Balazs Andor
*
******************************************************************************/
%option noyywrap
%option never-interactive
%option nounput
%{
/* Tokenizer for TTCN-3 Core Language */
#include "../../common/dbgnew.hh"
#include "compiler.h"
#include "../string.hh"
#include "../CompilerError.hh"
#include "../Real.hh"
#include "../Value.hh"
#include "AST_ttcn3.hh"
#include "Ttcnstuff.hh" // at least for PortTypeBody::PortOperationMode_t
#include "Statement.hh" // for Statement::statementtype_t
#include "Attributes.hh"
#include "../main.hh"
#include <string.h>
#include <ctype.h>
#include <openssl/md5.h>
namespace Common {
class IndexedValue;
class Location;
}
namespace Ttcn {
class ParamRedirect;
class Statement;
class AltGuard;
class IfClause;
class IfClauses;
class NamedTemplate;
class NamedTemplates;
class IndexedTemplate;
class IndexedTemplates;
class Templates;
class CompTypeRefList;
}
using namespace Common;
using namespace Ttcn;
#include "compiler.tab.hh"
#define yylval ttcn3_lval
#define yylloc ttcn3_lloc
/* global variable indicating the location of the returned token to bison */
extern YYLTYPE yylloc;
extern bool is_erroneous_parsed;
/* always points to the first character of the regexp to be recognized */
static size_t current_line, current_column;
/* when reporting an error in linemarker or preprocessor
* directive the real file name and line number is needed */
static const char* real_infile;
/* real_lineno = current_line + real_lineno_offset */
static int real_lineno_offset;
static bool dot_flag = false;
/* type of the backup token (that was found after a dot) */
static int backup_token;
/* semantic value of the backup token */
static YYSTYPE backup_lval;
/* location of the backup token */
static YYLTYPE backup_lloc;
static MD5_CTX md5_ctx;
static void fill_location()
{
yylloc.first_line = current_line;
yylloc.first_column = current_column;
current_column += yyleng;
yylloc.last_line = current_line;
yylloc.last_column = current_column;
}
static void update_md5()
{
MD5_Update(&md5_ctx, yytext, yyleng);
MD5_Update(&md5_ctx, " ", 1);
}
#define RETURN_SAVED_DOT \
do { \
yytext[0] = '\0'; \
yylloc.first_line = dot_line; \
yylloc.first_column = dot_column; \
yylloc.last_line = dot_line; \
yylloc.last_column = dot_column + 1; \
return '.'; \
} while (0)
/* return macro for simple tokens without semantic value */
#define RETURN(ret_val) \
do { \
update_md5(); \
fill_location(); \
if (dot_flag) { \
backup_token = ret_val; \
backup_lloc = yylloc; \
RETURN_SAVED_DOT; \
} else return ret_val; \
} while (0)
/* same as RETURN(ret_val) macro but without location update,
* usually a return after an error */
#define RETURN_NOLOCUPD(ret_val) \
do { \
update_md5(); \
if (dot_flag) { \
backup_token = ret_val; \
backup_lloc = yylloc; \
RETURN_SAVED_DOT; \
} else return ret_val; \
} while (0)
/* return macro for simple tokens with semantic value */
#define RETURN_LVAL(ret_val) \
do { \
update_md5(); \
fill_location(); \
if (dot_flag) { \
backup_token = ret_val; \
backup_lval = yylval; \
backup_lloc = yylloc; \
RETURN_SAVED_DOT; \
} else return ret_val; \
} while (0)
/* return macro for special tokens that are glued together with previous dot */
#define RETURN_DOT(ret_val) \
do { \
update_md5(); \
if (dot_flag) { \
dot_flag = false; \
yylloc.first_line = dot_line; \
yylloc.first_column = dot_column; \
current_column += yyleng; \
yylloc.last_line = current_line; \
yylloc.last_column = current_column; \
return Dot##ret_val; \
} else { \
fill_location(); \
return ret_val; \
} \
} while (0)
extern string *parse_charstring_value(const char *str, const Location& loc);
%}
NUMBER 0|([1-9][0-9]*)
FLOAT ({NUMBER}\.[0-9]+)|({NUMBER}(\.[0-9]+)?[Ee][+-]?{NUMBER})
IDENTIFIER [A-Za-z][A-Za-z0-9_]*
LINECOMMENT "//"[^\r\n]*
WHITESPACE [ \t\v\f]
NEWLINE \r|\n|\r\n
LINEMARKER {NUMBER}{WHITESPACE}+\"([^\\\"\r\n]|\\[^\r\n])*\"
UID [uU][+]?[0-9A-Fa-f]{1,8}
TITAN "$#&&&(#TITANERRONEOUS$#&&^#% "
TITAN2 "$#&&&(#TITANJSONDEFAULT$#&&^#% "
%x SC_blockcomment SC_cstring
%x SC_binstring SC_binstring_bad
%s SC_charkeyword
%%
/* local variables of yylex() */
size_t start_line = 0, start_column = 0; /**< used by block comments and
string literals */
size_t dot_line = 0, dot_column = 0; /**< location of the previous '.' token */
/* variables used when processing binary strings */
expstring_t origbinstr = NULL; /**< the string itself */
expstring_t binstr = NULL; /**< the string itself (with capital letters) */
bool valid_bit = false, /**< binstr is valid bitstring */
valid_oct = false, /**< binstr is valid octetstring */
half_oct = false, /**< binstr is not a valid octetstr but a valid hexstr */
contains_match = false, /**< binstr contains matching symbol */
contains_ws = false; /**< binstr contains whitespace characters */
if (dot_flag) {
if (backup_token == '.') {
/* Two dots were found in the previous call: the first one was returned,
* the second one is now in the backup. Let's assume that we have just
* found the second one. */
dot_line = backup_lloc.first_line;
dot_column = backup_lloc.first_column;
} else {
/* Return the token and its semantic value that was backed up after the
* last token (which was a dot). */
dot_flag = false;
yylval = backup_lval;
yylloc = backup_lloc;
return backup_token;
}
}
{TITAN} {
// hack: to avoid the erroneous parsing reporting a syntax error where it
// also lists TTCN3ModuleKeyword as a possible nonterminal to use
if (is_erroneous_parsed) {
RETURN(TitanErroneousHackKeyword);
} else {
Location loc(infile, current_line, current_column, current_line,
current_column + yyleng);
loc.error("Unexpected `%s'.", yytext);
}
}
{TITAN2} {
RETURN(TitanJsonDefaultHackKeyword);
}
/* Eat up comments and whitespaces */
"/*" {
start_line = current_line;
start_column = current_column;
current_column += 2;
BEGIN(SC_blockcomment);
}
<SC_blockcomment> /* -------- SC_blockcomment scope -------------- */
{
"*/" {
current_column += 2;
BEGIN(INITIAL);
}
{NEWLINE} {
current_line++;
current_column = 0;
}
. current_column++;
} /* SC_blockcomment */
{LINECOMMENT}?{NEWLINE} {
current_line++;
current_column = 0;
}
{LINECOMMENT} {
current_column += yyleng;
}
{WHITESPACE}+ current_column += yyleng;
/* C preprocessor line markers */
^{WHITESPACE}*"#"({WHITESPACE}*"line")?{WHITESPACE}+{LINEMARKER}[^\r\n]*{NEWLINE} {
bool error_flag = false;
int real_lineno = current_line + real_lineno_offset;
/* skipping the leading whitespaces */
int marker_begin = 0;
while (yytext[marker_begin] != '#') marker_begin++;
/* skipping the trailing whitespaces and newline */
int marker_end = yyleng - 1;
while (yytext[marker_end] == '\r' || yytext[marker_end] == '\n' ||
yytext[marker_end] == ' ' || yytext[marker_end] == '\t') marker_end--;
marker_end++;
Location loc(real_infile, real_lineno, current_column + marker_begin,
real_lineno, current_column + marker_end);
Error_Context cntxt(&loc, "In preprocessor line marker");
/* parsing out the line number */
int lineno_begin = marker_begin + 1;
while (!isdigit(static_cast<unsigned char>( yytext[lineno_begin] ))) lineno_begin++;
int lineno_end = lineno_begin + 1;
while (isdigit(static_cast<int>( yytext[lineno_end] ))) lineno_end++;
errno = 0;
int new_lineno = strtol(yytext + lineno_begin, NULL, 10);
if (errno != 0) {
Location lineno_loc(real_infile, real_lineno, current_column + lineno_begin,
real_lineno, current_column + lineno_end);
string lineno_str(lineno_end - lineno_begin, yytext + lineno_begin);
lineno_loc.error("Line number `%s' is too large for being represented in "
"memory: %s", lineno_str.c_str(), strerror(errno));
error_flag = true;
}
/* parsing out the file name */
int filename_begin = lineno_end + 1;
while (yytext[filename_begin] != '"') filename_begin++;
filename_begin++;
int filename_end = filename_begin;
while (yytext[filename_end] != '"') {
if (yytext[filename_end] == '\\') filename_end += 2;
else filename_end++;
}
Location filename_loc(real_infile, real_lineno, current_column +
filename_begin - 1, real_lineno, current_column + filename_end + 1);
string filename_str(filename_end - filename_begin, yytext + filename_begin);
string *parsed_filename = parse_charstring_value(filename_str.c_str(),
filename_loc);
if (!parsed_filename) error_flag = true;
/* updating the line/column counters */
if (error_flag) {
/* the line marker is erroneous, use the real line numbers */
infile = real_infile;
current_line = real_lineno + 1;
real_lineno_offset = 0;
} else {
/* set the given line number */
infile = Location::add_source_file_name(*parsed_filename);
current_line = new_lineno;
real_lineno_offset = real_lineno + 1 - new_lineno;
}
current_column = 0;
delete parsed_filename;
}
^{WHITESPACE}*"#"[^\r\n]* {
int real_lineno = current_line + real_lineno_offset;
/* skip the leading and trailing whitespaces */
int marker_begin = 0;
while (yytext[marker_begin] != '#') marker_begin++;
int marker_end = yyleng - 1;
while (yytext[marker_end] == ' ' || yytext[marker_end] == '\t') marker_end--;
marker_end++;
Location loc(real_infile, real_lineno, current_column + marker_begin,
real_lineno, current_column + marker_end);
loc.error("Invalid/unsupported preprocessor directive or line marker: `%s'",
string(marker_end - marker_begin, yytext + marker_begin).c_str());
current_column += yyleng;
}
/* Keywords */
action RETURN(ActionKeyword);
activate RETURN(ActivateKeyword);
address RETURN(AddressKeyword);
alive RETURN_DOT(AliveKeyword);
all RETURN(AllKeyword);
alt RETURN(AltKeyword);
altstep RETURN(AltstepKeyword);
and RETURN(AndKeyword);
and4b RETURN(And4bKeyword);
any RETURN(AnyKeyword);
anytype RETURN(AnyTypeKeyword);
apply RETURN_DOT(ApplyKeyword);
bitstring RETURN(BitStringKeyword);
boolean RETURN(BooleanKeyword);
break RETURN(BreakKeyword);
call RETURN_DOT(CallOpKeyword);
case RETURN(CaseKeyword);
catch RETURN_DOT(CatchOpKeyword);
char { BEGIN(SC_charkeyword); RETURN(CharKeyword); }
charstring RETURN(CharStringKeyword);
checkstate RETURN_DOT(CheckStateKeyword);
check RETURN_DOT(CheckOpKeyword);
clear RETURN_DOT(ClearOpKeyword);
complement RETURN(ComplementKeyword);
component RETURN(ComponentKeyword);
conjunct RETURN(ConjunctKeyword);
connect RETURN(ConnectKeyword);
const RETURN(ConstKeyword);
continue RETURN(ContinueKeyword);
control RETURN(ControlKeyword);
create RETURN_DOT(CreateKeyword);
decmatch RETURN(DecodedMatchKeyword);
deactivate RETURN(DeactivateKeyword);
default RETURN(DefaultKeyword);
derefers RETURN(DerefersKeyword);
disconnect RETURN(DisconnectKeyword);
display RETURN(DisplayKeyword);
do RETURN(DoKeyword);
done RETURN_DOT(DoneKeyword);
else RETURN(ElseKeyword);
encode RETURN(EncodeKeyword);
enumerated RETURN(EnumKeyword);
error RETURN(ErrorKeyword);
except RETURN(ExceptKeyword);
exception RETURN(ExceptionKeyword);
execute RETURN(ExecuteKeyword);
extends RETURN(ExtendsKeyword);
extension RETURN(ExtensionKeyword);
external RETURN(ExtKeyword);
fail RETURN(FailKeyword);
false RETURN(FalseKeyword);
float RETURN(FloatKeyword);
for RETURN(ForKeyword);
friend RETURN(FriendKeyword);
from RETURN(FromKeyword);
function RETURN(FunctionKeyword);
getcall RETURN_DOT(GetCallOpKeyword);
getreply RETURN_DOT(GetReplyOpKeyword);
getverdict RETURN(GetVerdictKeyword);
goto RETURN(GotoKeyword);
group RETURN(GroupKeyword);
halt RETURN_DOT(HaltKeyword);
hexstring RETURN(HexStringKeyword);
if RETURN(IfKeyword);
ifpresent RETURN(IfPresentKeyword);
implies RETURN(ImpliesKeyword);
import RETURN(ImportKeyword);
in RETURN(InParKeyword);
inconc RETURN(InconcKeyword);
infinity RETURN(InfinityKeyword);
inout RETURN(InOutParKeyword);
integer RETURN(IntegerKeyword);
interleave RETURN(InterleavedKeyword);
kill RETURN_DOT(KillKeyword);
killed RETURN_DOT(KilledKeyword);
label RETURN(LabelKeyword);
language RETURN(LanguageKeyword);
length RETURN(LengthKeyword);
log RETURN(LogKeyword);
map RETURN(MapKeyword);
match RETURN(MatchKeyword);
message RETURN(MessageKeyword);
mixed RETURN(MixedKeyword);
mod RETURN(ModKeyword);
modifies RETURN(ModifiesKeyword);
module RETURN(TTCN3ModuleKeyword);
modulepar RETURN(ModuleParKeyword);
mtc RETURN(MTCKeyword);
noblock RETURN(NoBlockKeyword);
none RETURN(NoneKeyword);
not RETURN(NotKeyword);
not_a_number RETURN(NaNKeyword);
not4b RETURN(Not4bKeyword);
nowait RETURN(NowaitKeyword);
null RETURN(NullKeyword);
objid RETURN(ObjectIdentifierKeyword);
octetstring RETURN(OctetStringKeyword);
of RETURN(OfKeyword);
omit RETURN(OmitKeyword);
on RETURN(OnKeyword);
optional RETURN(OptionalKeyword);
or RETURN(OrKeyword);
or4b RETURN(Or4bKeyword);
out RETURN(OutParKeyword);
override RETURN(OverrideKeyword);
param RETURN(ParamKeyword);
pass RETURN(PassKeyword);
pattern RETURN(PatternKeyword);
permutation RETURN(PermutationKeyword);
port RETURN(PortKeyword);
present RETURN(PresentKeyword);
private RETURN(PrivateKeyword);
procedure RETURN(ProcedureKeyword);
public RETURN(PublicKeyword);
raise RETURN_DOT(RaiseKeyword);
read RETURN_DOT(ReadKeyword);
receive RETURN_DOT(ReceiveOpKeyword);
record RETURN(RecordKeyword);
recursive RETURN(RecursiveKeyword);
refers RETURN(RefersKeyword);
rem RETURN(RemKeyword);
repeat RETURN(RepeatKeyword);
reply RETURN_DOT(ReplyKeyword);
return RETURN(ReturnKeyword);
running RETURN_DOT(RunningKeyword);
runs RETURN(RunsKeyword);
select RETURN(SelectKeyword);
self RETURN(SelfKeyword);
send RETURN_DOT(SendOpKeyword);
sender RETURN(SenderKeyword);
set RETURN(SetKeyword);
setstate RETURN(SetstateKeyword);
setverdict RETURN(SetVerdictKeyword);
signature RETURN(SignatureKeyword);
start RETURN_DOT(StartKeyword);
stop RETURN_DOT(StopKeyword);
subset RETURN(SubsetKeyword);
superset RETURN(SupersetKeyword);
system RETURN(SystemKeyword);
template RETURN(TemplateKeyword);
testcase RETURN(TestcaseKeyword);
timeout RETURN_DOT(TimeoutKeyword);
timer RETURN(TimerKeyword);
to RETURN(ToKeyword);
trigger RETURN_DOT(TriggerOpKeyword);
true RETURN(TrueKeyword);
type RETURN(TypeDefKeyword);
union RETURN(UnionKeyword);
universal RETURN(UniversalKeyword);
unmap RETURN(UnmapKeyword);
value RETURN(ValueKeyword);
valueof RETURN(ValueofKeyword);
var RETURN(VarKeyword);
variant RETURN(VariantKeyword);
verdicttype RETURN(VerdictTypeKeyword);
while RETURN(WhileKeyword);
with RETURN(WithKeyword);
xor RETURN(XorKeyword);
xor4b RETURN(Xor4bKeyword);
/* condition-based keywords
* (can be switched to identifiers with a command line option) */
now {
if (realtime_features) {
RETURN(NowKeyword);
}
else {
Location loc(infile, yylloc);
loc.warning("Keyword 'now' is treated as an identifier. Activate compiler "
"option '-I' to use real-time testing features.");
yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
RETURN_LVAL(IDentifier);
}
}
realtime {
if (realtime_features) {
RETURN(RealtimeKeyword);
}
else {
Location loc(infile, yylloc);
loc.warning("Keyword 'realtime' is treated as an identifier. Activate "
"compiler option '-I' to use real-time testing features.");
yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
RETURN_LVAL(IDentifier);
}
}
timestamp {
if (realtime_features) {
RETURN(TimestampKeyword);
}
else {
Location loc(infile, yylloc);
loc.warning("Keyword 'timestamp' is treated as an identifier. Activate "
"compiler option '-I' to use real-time testing features.");
yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
RETURN_LVAL(IDentifier);
}
}
class {
if (oop_features) {
RETURN(ClassKeyword);
}
else {
Location loc(infile, yylloc);
loc.warning("Keyword 'class' is treated as an identifier. Activate "
"compiler option '-k' to use object-oriented features.");
yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
RETURN_LVAL(IDentifier);
}
}
finally {
if (oop_features) {
RETURN(FinallyKeyword);
}
else {
Location loc(infile, yylloc);
loc.warning("Keyword 'finally' is treated as an identifier. Activate "
"compiler option '-k' to use object-oriented features.");
yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
RETURN_LVAL(IDentifier);
}
}
this {
if (oop_features) {
RETURN(ThisKeyword);
}
else {
Location loc(infile, yylloc);
loc.warning("Keyword 'this' is treated as an identifier. Activate "
"compiler option '-k' to use object-oriented features.");
yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
RETURN_LVAL(IDentifier);
}
}
super {
if (oop_features) {
RETURN(SuperKeyword);
}
else {
Location loc(infile, yylloc);
loc.warning("Keyword 'super' is treated as an identifier. Activate "
"compiler option '-k' to use object-oriented features.");
yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
RETURN_LVAL(IDentifier);
}
}
object {
if (oop_features) {
RETURN(ObjectKeyword);
}
else {
Location loc(infile, yylloc);
loc.warning("Keyword 'object' is treated as an identifier. Activate "
"compiler option '-k' to use object-oriented features.");
yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
RETURN_LVAL(IDentifier);
}
}
/* modifier keywords */
"@nocase" RETURN(NocaseKeyword);
"@lazy" RETURN(LazyKeyword);
"@decoded" RETURN(DecodedKeyword);
"@deterministic" RETURN(DeterministicKeyword);
"@fuzzy" RETURN(FuzzyKeyword);
"@index" RETURN(IndexKeyword);
"@local" RETURN(LocalKeyword);
"@final" RETURN(FinalKeyword);
"@abstract" RETURN(AbstractKeyword);
"@default" RETURN(DefaultModifier);
"@dynamic" RETURN(DynamicModifier);
/* special TITAN specific keywords */
"@try" RETURN(TitanSpecificTryKeyword);
"@catch" RETURN(TitanSpecificCatchKeyword);
"@profiler" RETURN(TitanSpecificProfilerKeyword);
"@update" RETURN(TitanSpecificUpdateKeyword);
"getref" RETURN_DOT(GetRefKeyword);
/* Predefined function identifiers */
bit2hex RETURN(bit2hexKeyword);
bit2int RETURN(bit2intKeyword);
bit2oct RETURN(bit2octKeyword);
bit2str RETURN(bit2strKeyword);
bson2json RETURN(bson2JsonKeyword);
cbor2json RETURN(cbor2JsonKeyword);
char2int RETURN(char2intKeyword);
char2oct RETURN(char2octKeyword);
decomp RETURN(decompKeyword);
float2int RETURN(float2intKeyword);
float2str RETURN(float2strKeyword);
hex2bit RETURN(hex2bitKeyword);
hex2int RETURN(hex2intKeyword);
hex2oct RETURN(hex2octKeyword);
hex2str RETURN(hex2strKeyword);
int2bit RETURN(int2bitKeyword);
int2char RETURN(int2charKeyword);
int2enum RETURN(int2enumKeyword);
int2float RETURN(int2floatKeyword);
int2hex RETURN(int2hexKeyword);
int2oct RETURN(int2octKeyword);
int2str RETURN(int2strKeyword);
int2unichar RETURN(int2unicharKeyword);
isvalue RETURN(isvalueKeyword);
isbound RETURN(isboundKeyword);
ischosen RETURN(ischosenKeyword);
ispresent RETURN(ispresentKeyword);
istemplatekind RETURN(istemplatekindKeyword);
json2bson RETURN(json2bsonKeyword);
json2cbor RETURN(json2CborKeyword);
lengthof RETURN(lengthofKeyword);
oct2bit RETURN(oct2bitKeyword);
oct2char RETURN(oct2charKeyword);
oct2hex RETURN(oct2hexKeyword);
oct2int RETURN(oct2intKeyword);
oct2str RETURN(oct2strKeyword);
regexp RETURN(regexpKeyword);
replace RETURN(replaceKeyword);
rnd RETURN(rndKeyword);
setencode RETURN_DOT(SetencodeKeyword);
sizeof RETURN(sizeofKeyword);
str2bit RETURN(str2bitKeyword);
str2float RETURN(str2floatKeyword);
str2hex RETURN(str2hexKeyword);
str2int RETURN(str2intKeyword);
str2oct RETURN(str2octKeyword);
substr RETURN(substrKeyword);
unichar2int RETURN(unichar2intKeyword);
unichar2char RETURN(unichar2charKeyword);
log2str RETURN(log2strKeyword);
enum2int RETURN(enum2intKeyword);
encvalue RETURN(encvalueKeyword);
decvalue RETURN(decvalueKeyword);
testcasename RETURN(testcasenameKeyword);
ttcn2string RETURN(ttcn2stringKeyword);
string2ttcn RETURN(string2ttcnKeyword);
unichar2oct RETURN(unichar2octKeyword);
oct2unichar RETURN(oct2unicharKeyword);
remove_bom RETURN(remove_bomKeyWord);
get_stringencoding RETURN(get_stringencodingKeyWord);
encode_base64 RETURN(encode_base64KeyWord);
decode_base64 RETURN(decode_base64KeyWord);
encvalue_unichar RETURN(encvalue_unicharKeyWord);
decvalue_unichar RETURN(decvalue_unicharKeyWord);
any2unistr RETURN(any2unistrKeyWord);
hostid RETURN(hostidKeyWord);
/* Values */
{NUMBER} {
Location loc(infile, current_line, current_column, current_line,
current_column + yyleng);
yylval.int_val = new int_val_t(yytext, loc);
RETURN_LVAL(Number);
}
{FLOAT} {
Location loc(infile, current_line, current_column, current_line,
current_column + yyleng);
yylval.float_val = string2Real(yytext, loc);
RETURN_LVAL(FloatValue);
}
NULL RETURN(NullValue);
"'" {
origbinstr=memptystr();
binstr=memptystr();
valid_bit=true;
valid_oct=true;
half_oct=false;
contains_match=false;
contains_ws=false;
start_line = current_line;
start_column = current_column;
current_column++;
MD5_Update(&md5_ctx, yytext, yyleng);
BEGIN(SC_binstring);
}
\" {
yylval.str = memptystr();
start_line = current_line;
start_column = current_column;
current_column++;
MD5_Update(&md5_ctx, yytext, yyleng);
BEGIN(SC_cstring);
}
<SC_charkeyword>
{
{UID} {
yylval.str = mcopystrn(yytext, yyleng);
RETURN_LVAL(Cstring);
}
[,] { RETURN(*yytext); }
[)] { BEGIN(INITIAL); RETURN(*yytext); }
}
<SC_binstring> /* -------- SC_binstring scope -------------- */
{
{WHITESPACE}+ {
contains_ws = true;
current_column += yyleng;
}
{WHITESPACE}*{NEWLINE} {
contains_ws = true;
current_line++;
current_column = 0;
}
[01] {
origbinstr = mputc(origbinstr, yytext[0]);
binstr = mputc(binstr, yytext[0]);
half_oct = !half_oct;
current_column++;
}
[2-9A-F] {
origbinstr = mputc(origbinstr, yytext[0]);
binstr = mputc(binstr, yytext[0]);
valid_bit = false;
half_oct = !half_oct;
current_column++;
}
[a-f] {
origbinstr = mputc(origbinstr, yytext[0]);
binstr = mputc(binstr, yytext[0] - 'a' + 'A');
valid_bit = false;
half_oct = !half_oct;
current_column++;
}
"?"|"*" {
origbinstr = mputc(origbinstr, yytext[0]);
binstr = mputc(binstr, yytext[0]);
contains_match = true;
if (half_oct) valid_oct = false;
current_column++;
}
"'"[bBhHoO] {
yylloc.first_line = start_line;
yylloc.first_column = start_column;
yylloc.last_line = current_line;
yylloc.last_column = current_column + 2;
Location loc(infile, yylloc);
int ret_val = TOK_errval;
switch (yytext[1]) {
case 'b': {
Location loc2(infile, current_line, current_column + 1, current_line,
current_column + 2);
loc2.warning("The last character of a bitstring literal should be "
"`B' instead of `b'");
/* no break */ }
case 'B':
if (valid_bit) {
if (contains_ws) loc.warning("Bitstring %s contains whitespace and/or "
"newline character(s)", contains_match ? "match" : "value");
ret_val = contains_match ? BitStringMatch : Bstring;
yylval.string_val = new string(binstr);
} else loc.error("Bitstring value contains invalid character");
break;
case 'h': {
Location loc2(infile, current_line, current_column + 1, current_line,
current_column + 2);
loc2.warning("The last character of a hexstring literal should be "
"`H' instead of `h'");
/* no break */ }
case 'H':
if (contains_ws) loc.warning("Hexstring %s contains whitespace and/or "
"newline character(s)", contains_match ? "match" : "value");
ret_val = contains_match ? HexStringMatch : Hstring;
yylval.string_val = new string(binstr);
break;
case 'o': {
Location loc2(infile, current_line, current_column + 1, current_line,
current_column + 2);
loc2.warning("The last character of an octetstring literal should be "
"`O' instead of `o'");
/* no break */ }
case 'O':
if (valid_oct && !half_oct) {
if (contains_ws) loc.warning("Octetstring %s contains whitespace "
"and/or newline character(s)", contains_match ? "match" : "value");
ret_val = contains_match ? OctetStringMatch : Ostring;
yylval.string_val = new string(binstr);
} else if (contains_match) {
loc.error("Octetstring match contains half octet(s)");
} else {
loc.error("Octetstring value contains odd number of hexadecimal "
"digits");
}
}
MD5_Update(&md5_ctx, origbinstr, strlen(origbinstr));
Free(origbinstr);
Free(binstr);
update_md5();
BEGIN(INITIAL);
current_column += 2;
if (dot_flag) {
backup_token = ret_val;
backup_lval = yylval;
backup_lloc = yylloc;
RETURN_SAVED_DOT;
} else return ret_val;
}
"'" {
yylloc.first_line = start_line;
yylloc.first_column = start_column;
current_column++;
yylloc.last_line = current_line;
yylloc.last_column = current_column;
Location loc(infile, yylloc);
loc.error("Invalid binary string literal. Expecting `B', `H' or `O' after "
"the closing `''");
MD5_Update(&md5_ctx, origbinstr, strlen(origbinstr));
Free(origbinstr);
Free(binstr);
BEGIN(INITIAL);
RETURN_NOLOCUPD(TOK_errval);
}
. {
Location loc(infile, current_line, current_column, current_line,
current_column + 1);
int c = static_cast<unsigned char>( yytext[0] );
loc.error("Invalid character `%c' (0x%02X) in binary string",
isprint(c) ? c : '?', c);
MD5_Update(&md5_ctx, origbinstr, strlen(origbinstr));
Free(origbinstr);
Free(binstr);
MD5_Update(&md5_ctx, yytext, 1);
current_column++;
BEGIN(SC_binstring_bad);
}
} /* SC_binstring scope */
<SC_binstring_bad> /* -------- SC_binstring_bad scope -------------- */
{
{WHITESPACE}+ current_column += yyleng;
{WHITESPACE}*{NEWLINE} {
current_line++;
current_column = 0;
}
"'"[bBhHoO]? {
current_column += yyleng;
yylloc.first_line = start_line;
yylloc.first_column = start_column;
yylloc.last_line = current_line;
yylloc.last_column = current_column;
BEGIN(INITIAL);
RETURN_NOLOCUPD(TOK_errval);
}
. {
MD5_Update(&md5_ctx, yytext, yyleng);
current_column++;
}
} /* SC_binstring_bad scope */
<SC_cstring> /* -------- SC_cstring scope -------------- */
{
\\?{NEWLINE} { /* newline possibly preceded by backslash */
yylval.str = mputstr(yylval.str, yytext);
current_line++;
current_column = 0;
}
\"\"|\\. { /* two doublequotes or any backslash-escaped char */
yylval.str = mputstr(yylval.str, yytext);
current_column += 2;
/* Note that both get added ("external representation").
* parse_charstring_value() in charstring_la.l is responsible
* for transforming the string to "internal representation" */
}
\" {
current_column++;
yylloc.first_line = start_line;
yylloc.first_column = start_column;
yylloc.last_line = current_line;
yylloc.last_column = current_column;
MD5_Update(&md5_ctx, yylval.str, strlen(yylval.str));
update_md5();
BEGIN(INITIAL);
if (dot_flag) {
backup_token = Cstring;
backup_lval = yylval;
backup_lloc = yylloc;
RETURN_SAVED_DOT;
} else return Cstring;
}
. {
yylval.str = mputc(yylval.str, yytext[0]);
current_column++;
}
} /* SC_cstring scope */
/* Macros */
"%moduleId" {
yylval.macrotype = Value::MACRO_MODULEID;
RETURN_LVAL(MacroValue);
}
"%fileName" {
yylval.macrotype = Value::MACRO_FILENAME;
RETURN_LVAL(MacroValue);
}
"%lineNumber" {
yylval.macrotype = Value::MACRO_LINENUMBER;
RETURN_LVAL(MacroValue);
}
"%definitionId" {
yylval.macrotype = Value::MACRO_DEFINITIONID;
RETURN_LVAL(MacroValue);
}
"%testcaseId" {
yylval.macrotype = Value::MACRO_TESTCASEID;
RETURN_LVAL(MacroValue);
}
"%"{IDENTIFIER} {
fill_location();
Location loc(infile, yylloc);
loc.error("Invalid macro notation: `%s'", yytext);
RETURN_NOLOCUPD(TOK_errval);
}
"__MODULE__" {
yylval.macrotype = Value::MACRO_MODULEID;
RETURN_LVAL(MacroValue);
}
"__FILE__" {
yylval.macrotype = Value::MACRO_FILEPATH;
RETURN_LVAL(MacroValue);
}
"__BFILE__" {
yylval.macrotype = Value::MACRO_BFILENAME;
RETURN_LVAL(MacroValue);
}
"__LINE__" {
yylval.macrotype = Value::MACRO_LINENUMBER_C;
RETURN_LVAL(MacroValue);
}
"__SCOPE__" {
yylval.macrotype = Value::MACRO_SCOPE;
RETURN_LVAL(MacroValue);
}
"__TESTCASE__" {
yylval.macrotype = Value::MACRO_TESTCASEID;
RETURN_LVAL(MacroValue);
}
"__"{IDENTIFIER}"__" {
fill_location();
Location loc(infile, yylloc);
loc.error("Invalid macro notation: `%s'", yytext);
RETURN_NOLOCUPD(TOK_errval);
}
/* Multi-character operators */
":=" RETURN(AssignmentChar);
"\.\." RETURN(DotDot);
"->" RETURN(PortRedirectSymbol);
"==" RETURN(EQ);
"!=" RETURN(NE);
">=" RETURN(GE);
"<=" RETURN(LE);
"<<" RETURN(SL);
">>" RETURN(SR);
"<@" RETURN(RL);
"@>" RETURN(_RR);
"++" |
"--" {
fill_location();
Location loc(infile, yylloc);
loc.error("Operator `%s' is reserved for future use", yytext);
}
/* Invalid operators */
"::=" {
fill_location();
Location loc(infile, yylloc);
loc.error("`::=' is not a valid assignment operator in TTCN-3. Did you mean "
"`:='?");
RETURN_NOLOCUPD(AssignmentChar);
}
"=" {
fill_location();
Location loc(infile, yylloc);
loc.error("A single `=' character cannot be used in TTCN-3. Did you mean "
"the assignment sign `:=' or the equality operator `=='?");
/* the former is more probable than the latter */
RETURN_NOLOCUPD(AssignmentChar);
}
"<>" {
fill_location();
Location loc(infile, yylloc);
loc.error("`<>' is not a valid comparison operator in TTCN-3. Did you mean "
"`!='?");
RETURN_NOLOCUPD(NE);
}
"=>" RETURN(ClassCastingSymbol);
/* Identifiers */
{IDENTIFIER} {
yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
RETURN_LVAL(IDentifier);
}
/* Single character tokens (brackets, operators, etc.) */
\. {
update_md5();
if (dot_flag) {
/* store this dot in the backup */
backup_token = '.';
backup_lloc.first_line = current_line;
backup_lloc.first_column = current_column;
current_column++;
backup_lloc.last_line = current_line;
backup_lloc.last_column = current_column;
/* return the dot that was found previously */
RETURN_SAVED_DOT;
} else {
dot_flag = true;
dot_line = current_line;
dot_column = current_column;
current_column++;
}
}
[()\[\]{}+\-\*/&:;,<>\?!] RETURN(*yytext);
/* Invalid characters */
. {
fill_location();
Location loc(infile, yylloc);
int c = static_cast<unsigned char>( yytext[0] );
loc.error("Character `%c' (0x%02X) is not used in TTCN-3",
isprint(c) ? c : '?', c);
}
/* EOF rule */
<*><<EOF>> {
if (YY_START != INITIAL) {
Location loc(infile, start_line, start_column, current_line,
current_column);
switch (YY_START) {
case SC_blockcomment:
loc.error("Unterminated block comment");
break;
case SC_binstring:
Free(origbinstr);
Free(binstr);
/* no break */
case SC_binstring_bad:
loc.error("Unterminated binary string literal");
break;
case SC_cstring:
Free(yylval.str);
loc.error("Unterminated character string literal");
}
BEGIN(INITIAL);
}
if (dot_flag) {
dot_flag = false;
RETURN_SAVED_DOT;
} else {
yylloc.first_line = current_line;
yylloc.first_column = current_column;
yylloc.last_line = current_line;
yylloc.last_column = current_column + 1;
return EOF;
}
}
%%
void init_ttcn3_lex()
{
dot_flag = false;
current_line = 1;
current_column = 0;
real_infile = infile;
real_lineno_offset = 0;
MD5_Init(&md5_ctx);
}
void init_erroneous_lex(const char* p_infile, size_t p_line, size_t p_column)
{
infile = p_infile;
current_line = p_line;
current_column = p_column;
real_infile = infile;
real_lineno_offset = 0;
dot_flag = false;
}
void free_dot_flag_stuff()
{
if (dot_flag) {
dot_flag = false;
/* clean up the semantic value of the token that was backed up */
switch (backup_token) {
case IDentifier:
delete backup_lval.id;
break;
case Bstring:
case Hstring:
case Ostring:
case BitStringMatch:
case HexStringMatch:
case OctetStringMatch:
delete backup_lval.string_val;
break;
case Cstring:
Free(backup_lval.str);
default:
break;
}
}
}
void free_ttcn3_lex()
{
free_dot_flag_stuff();
fclose(ttcn3_in);
ttcn3_lex_destroy();
}
/* called from ttcn3_parse_file to finalize MD5 and add it to the module */
void set_md5_checksum(Ttcn::Module *m)
{
unsigned char md5_sum[MD5_DIGEST_LENGTH];
MD5_Final(md5_sum, &md5_ctx);
m->set_checksum(sizeof(md5_sum), md5_sum);
}