/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

%{
#include <iostream>
#include <cerrno>
#include <climits>
#include <cstdlib>
#include <string>

#include "parser.hpp"  // 包含由parser.y生成的头文件
#include "scanner.h"   // 包含yyFlexLexer子类的头文件
#include "location.hh" // 包含位置调试信息头文件

/* 定义了YY_USER_ACTION,该宏在每个记号的语义动作之前被调用,来根据记号的长度设置位置的信息 */
#define YY_USER_ACTION  loc.columns (yyleng);

using namespace Uscript;
#define yyterminate() Parser::make_END(loc);
%}

/* 声明使用C++版本FLEXER */
%option c++

%option noyywrap

/* 使用Scanner::yylex() */
%option yyclass="Scanner"

/* 一些与编译常量使用该前缀否则为yy */
%option prefix="script_"

%%
%{
  // C++ 兼容的词法分析器的规则,step函数把位置的起始值设置为与结束值相等
  loc.step();
%}

"#".*    {
            loc.step(); // 注释
}

"/*"([^\*]|(\*)*[^\*/])*(\*)*"*/" {
            loc.step(); // 注释
}

"//".* |
[ \t]     {
            /* 跳过注释和空白符号 
             * step函数把位置的起始值设置为与结束值相等,这样位置就指向了上一个极少的结束位置。
             * 由于注释和空白符号识别后并不会返回,而前一个step的调用是在上一次yylex返回时,所以此处需要手动更新记号的起始位置
             */
            loc.step();
          }
\n        {
            loc.lines(yyleng); // 使用lines函数来更新位置信息中的行号
            loc.step();
          }

"function"  { return Parser::make_FUNCTION(yytext, loc); }
"for"       { return Parser::make_FOR(yytext, loc); }
"while"     { return Parser::make_WHILE(yytext, loc); }
"if"        { return Parser::make_IF(yytext, loc); } //return IF;
"else"      { return Parser::make_ELSE(yytext, loc); } //return ELSE;
"+"         { return Parser::make_ADD(yytext, loc); } //return ADD;
"-"         { return Parser::make_SUB(yytext, loc); } //return SUB;
"*"         { return Parser::make_MUL(yytext, loc); } //return MUL;
"/"         { return Parser::make_DIV(yytext, loc); } //return DIV;
"="         { return Parser::make_ASSIGN(yytext, loc); } //return ASSIGN;
"=="        { return Parser::make_EQ(yytext, loc); } //return EQ;
"&&"        { return Parser::make_AND(yytext, loc); } //return AND;
"||"        { return Parser::make_OR(yytext, loc); } //return OR;
"!="        { return Parser::make_NE(yytext, loc); } //return NE;
">"         { return Parser::make_GT(yytext, loc); } //return GT;
">="        { return Parser::make_GE(yytext, loc); } //return GE;
"<"         { return Parser::make_LT(yytext, loc); } //return LT;
"<="        { return Parser::make_LE(yytext, loc); } //return LE;
"("         { return Parser::make_LP(yytext, loc); } //return LP;
")"         { return Parser::make_RP(yytext, loc); } //return RP;
"{"         { return Parser::make_LC(yytext, loc); } //return LC;
"}"         { return Parser::make_RC(yytext, loc); } //return RC;
";"         { return Parser::make_SEMICOLON(yytext, loc); } //return SEMICOLON;
"break"     { return Parser::make_BREAK(yytext, loc); } //return BREAK;
"continue"  { return Parser::make_CONTINUE(yytext, loc); } //return CONTINUE;
"return"    { return Parser::make_RETURN(yytext, loc); } //return RETURN;
","         { return Parser::make_COMMA(yytext, loc); } //return COMMA;

[A-Za-z_][A-Za-z_0-9]* {
    return Parser::make_IDENTIFIER(yytext, loc);
}
([1-9][0-9]*)|"0" {
    return Parser::make_NUMBER(std::strtol(yytext, nullptr, 10),loc);
}
[0-9]+\.[0-9]+ {
    char* end = nullptr;
    return Parser::make_FLOAT(std::strtof(yytext, &end), loc);
}

\"[^\n"]+\" {
    return Parser::make_STRING(std::string(yytext + 1, yyleng - 2), loc);
}
<<EOF>>   {
    return yyterminate();
}

.   {
    loc.step();
}
%%