【五】詞法解析器和語法解析器

前言

這個是腳本語言的起點扮授,我用的工具是bison和flex,PHP使用的是bison和re2c明刷,沒有太多差異

詞法解析器規(guī)則

%{
#include "skl_core.h"
#include "skl_variable.h"
#include "skl_function.h"
#include "skl_compiler.h"
#include "skl_language_parser.h"

void yyerror(char *);

int yywrap(void)
{
    return 1;
}

void yyerror(char *s) {
    printf("[Error] %s:%s(%d)\n",compiler_info.scanner_filename, s, compiler_info.scanner_line);
}
%}

%start COMMENT

%%

<INITIAL>"function"  return T_FUNCTION;
<INITIAL>"global"    return T_GLOBAL;
<INITIAL>"for"       return T_FOR;
<INITIAL>"if"        return T_IF;
<INITIAL>"else"        return T_ELSE;
<INITIAL>"+"         return T_ADD;
<INITIAL>"-"         return T_SUB;
<INITIAL>"*"         return T_MUL;
<INITIAL>"/"         return T_DIV;
<INITIAL>"="         return T_ASSIGN;
<INITIAL>"=="        return T_EQ;
<INITIAL>"!="        return T_NE;
<INITIAL>">"         return T_GT;
<INITIAL>">="        return T_GE;
<INITIAL>"<"         return T_LT;
<INITIAL>"<="        return T_LE;
<INITIAL>"("         return T_LP;
<INITIAL>")"         return T_RP;
<INITIAL>"{"         return T_LC;
<INITIAL>"}"         return T_RC;
<INITIAL>";"         return T_SEMICOLON;
<INITIAL>"break"     return T_BREAK;
<INITIAL>"continue"  return T_CONTINUE;
<INITIAL>"return"    return T_RETURN;
<INITIAL>"include"   return T_INCLUDE;
<INITIAL>","         return T_COMMA;

<INITIAL>[A-Za-z_][A-Za-z_0-9]*     {
    yylval.identifier = malloc_string(yytext);
    return T_IDENTIFIER;
}

<INITIAL>([1-9][0-9]*)|"0"          {
    int temp;
    sscanf(yytext ,"%d" ,&temp);
    yylval.integer = temp;
    return T_INT_LITERAL;
}

<INITIAL>[0-9]+\.[0-9]+             {
    double temp;
    sscanf(yytext, "%lf", &temp);
    yylval.db = temp;
    return T_DOUBLE_LITERAL;
}

<INITIAL>[ \t\r]                      ;
<INITIAL>"\n"                       {
    compiler_info.scanner_line++;
}
<INITIAL>("#"|"http://")[^\n]*           {
    BEGIN COMMENT;
}

<INITIAL>.                          {
    compiler_info.scanner_line++;
    yyerror(yytext);
}

<INITIAL>L?\"(\\.|[^\\"])*\" {
    yylval.identifier = malloc_string_trim(yytext);
    return T_STRING_LITERAL;
}

<COMMENT>\n                         {
    compiler_info.scanner_line++;
    BEGIN INITIAL;
}

<COMMENT>.                          ;
%%

標(biāo)識解釋

  • INITAL:解析程序語句標(biāo)識
  • COMMENT:程序注釋標(biāo)識

INITAL開頭就是對程序進行token解析,而COMMENT則是沒有卵用的魄藕,至于為什么這么寫就需要讀者自己去查看資料日麸。
要注意這些還只是詞法解析格式
執(zhí)行命令

flex --outfile=skl_language_scanner.c skl_language_scanner.l

生成的skl_language_scanner.c才是詞法解析器源碼。

語法解析器規(guī)則

%{
#include "skl_core.h"
#include "skl_variable.h"
#include "skl_function.h"
#include "skl_compiler.h"
#define YYDEBUG 1

%}

%union {
    char *identifier;
    int integer;
    double db;
    variable_t *variable;
    expression_t *expression;
    expression_list_t *expression_list;
    statement_t *statement;
    statement_list_t *statement_list;
    function_t *function;
    param_list_t *param_list;
}

%token <integer> T_INT_LITERAL
%token <db> T_DOUBLE_LITERAL

%token  <identifier>T_FUNCTION T_GLOBAL T_FOR T_IF T_ELSE T_ADD T_SUB T_MUL T_DIV T_ASSIGN
        T_EQ T_NE T_GT T_GE T_LT T_LE T_LP T_RP T_LC T_RC T_SEMICOLON T_IDENTIFIER
        T_BREAK T_CONTINUE T_RETURN T_COMMA T_STRING_LITERAL
        T_INCLUDE

%type <param_list> param_list

%type <expression_list> call_param_list

%type <function>function_definition
        
%type <expression> equality_expression relational_expression additive_expression multiplicative_expression primary_expression expression option_expression

%type <statement_list> statement_block statement_list

%type <statement> all_statement expression_statement return_statement continue_statement break_statement
                for_statement if_statement global_variable_declaration_statement
                cannot_top_statement can_top_statement include_statement

%%
// 運行單元
// 開始 函數(shù)定義 或 置頂?shù)恼Z句
translation_unit: function_definition
    | can_top_statement {
        set_global_statement_list($1);
    }
    | translation_unit can_top_statement
    {
        set_global_statement_list($2);
    }
    | translation_unit cannot_top_statement{
        set_global_statement_list($2);
    }
    | translation_unit function_definition
    ;

// 函數(shù)定義
function_definition: T_FUNCTION T_IDENTIFIER T_LP param_list T_RP statement_block
    {
        create_function($2 ,$4 ,$6);
    }
    | T_FUNCTION T_IDENTIFIER T_LP T_RP statement_block
    {
        create_function($2 ,NULL ,$5);
    }
    ;

// 能置頂語句
can_top_statement: expression_statement
    | global_variable_declaration_statement
    | for_statement
    | if_statement
    | return_statement
    | include_statement
    ;

// 不能置頂語句
cannot_top_statement: break_statement
    | continue_statement
    ;
// 所有的語句
all_statement: can_top_statement
    | cannot_top_statement
    ;

// 包含表達(dá)式
include_statement: T_INCLUDE T_STRING_LITERAL T_SEMICOLON
    {
        $$ = create_include_statment($2);
    }
    ;
// 表達(dá)式語句
// 例子: 1+2+3;(雖然無用)
expression_statement: expression T_SEMICOLON
    {
        $$ = create_expression_statement($1);
    }
    ;

// for語句
for_statement: T_FOR T_LP option_expression T_SEMICOLON option_expression T_SEMICOLON option_expression T_RP statement_block
    {
        $$ = create_for_statement($3 ,$5 ,$7 ,$9);
    }
    ;

// break語句
break_statement: T_BREAK T_SEMICOLON
    {
        $$ = create_break_statement();
    }
    ;

// if語句
if_statement: T_IF T_LP expression T_RP statement_block
    {
        $$ = create_if_statement($3 ,$5 ,NULL);
    }
    | T_IF T_LP expression T_RP statement_block T_ELSE statement_block
    {
        $$ = create_if_statement($3 ,$5 ,$7);
    }
    ;

// return語句
return_statement: T_RETURN option_expression T_SEMICOLON
    {
        $$ = create_return_statement($2);
    }
    ;

// 全局變量定義語句
// 例子: gloabl var1 = 4; | global var1;
global_variable_declaration_statement: T_GLOBAL T_IDENTIFIER T_SEMICOLON
    {
        $$ = create_global_variable_statement($2, NULL);
    }
    |T_GLOBAL T_IDENTIFIER T_ASSIGN expression T_SEMICOLON
    {
        $$ = create_global_variable_statement($2, $4);
    }
    ;

// 語句列表
statement_list:  all_statement
    {
        $$ = create_statement_list($1);
    }
    | statement_list all_statement
    {
        $$ = insert_statement_list($1 ,$2);
    }
    ;

// 語句塊
statement_block: T_LC  T_RC
    {
        $$ = NULL;
    }
    | T_LC statement_list T_RC
    {
        $$ = $2;
    }
    ;

// continue語句
continue_statement: T_CONTINUE T_SEMICOLON
    {
        $$ = create_continue_statement();
    }
    ;

// 所有表達(dá)式
expression: equality_expression
    | T_IDENTIFIER T_ASSIGN expression
    {
        $$ = create_assign_expression($1 ,$3);
    }
    ;

// 等值表達(dá)式
equality_expression: relational_expression
    | equality_expression T_EQ relational_expression
    {
        $$ = create_binary_expression(expression_action_eq ,$1,$3);
    }
    | equality_expression T_NE relational_expression
    {
        $$ = create_binary_expression(expression_action_ne ,$1,$3);
    }
    ;

// 關(guān)聯(lián)表達(dá)式(加法)
relational_expression: additive_expression
    | relational_expression T_LT additive_expression
    {
        $$ = create_binary_expression(expression_action_lt ,$1,$3);
    }
    | relational_expression T_GT additive_expression
    {
        $$ = create_binary_expression(expression_action_gt ,$1,$3);
    }
    | relational_expression T_LE additive_expression
    {
        $$ = create_binary_expression(expression_action_le ,$1,$3);
    }
    | relational_expression T_GE additive_expression
    {
        $$ = create_binary_expression(expression_action_ge ,$1,$3);
    }
    ;

// 加法表達(dá)式
additive_expression: multiplicative_expression
    | additive_expression T_ADD multiplicative_expression
    {
        $$ = create_binary_expression(expression_action_add ,$1,$3);
    }
    | additive_expression T_SUB multiplicative_expression
    {
        $$ = create_binary_expression(expression_action_sub ,$1,$3);
    }
    ;

// 乘除表達(dá)式
multiplicative_expression: primary_expression
    | multiplicative_expression T_DIV primary_expression
    {
        $$ = create_binary_expression(expression_action_div ,$1,$3);
    }
    | multiplicative_expression T_MUL primary_expression
    {
        $$ = create_binary_expression(expression_action_mul ,$1,$3);
    }
    ;

// 基礎(chǔ)表達(dá)式
primary_expression:T_SUB primary_expression
    {
        $$ = $2;
    }
    | T_LP expression T_RP
    {
        $$ = $2;
    }
    | T_IDENTIFIER
    {
        $$ = create_identifier_expression($1);
    }
    | T_STRING_LITERAL
    {
        $$ = create_string_expression($1);
    }
    | T_INT_LITERAL
    {
        $$ = create_integer_expression($1);
    }
    | T_DOUBLE_LITERAL
    {
        $$ = create_double_expression($1);
    }
    | T_IDENTIFIER T_LP T_RP
    {
        $$ = create_call_function_expression($1 ,NULL);
    }
    | T_IDENTIFIER T_LP call_param_list T_RP
    {
        $$ = create_call_function_expression($1 ,$3);
    }
    ;

// 可選表達(dá)式
option_expression: expression
    | {$$=NULL;}
    ;

// 參數(shù)列表
param_list: T_IDENTIFIER
    {
        $$ = create_param_list($1);
    }
    | param_list T_COMMA T_IDENTIFIER
    {
        $$ = insert_param_list($1 ,$3);
    }
    ;

// 調(diào)用參數(shù)列表
call_param_list: expression
    {
        $$ = create_call_param_list($1);
    }
    | call_param_list T_COMMA expression
    {
        $$ = insert_call_param_list($1 ,$3);
    }
    ;

這個規(guī)則很長纽哥,之前我也看過PHP钠乏,更長,幾千行春塌,看著煩晓避,但是作為語法特性實現(xiàn),就是需要這么長只壳。
這個規(guī)則也是我歷經(jīng)一個月一邊學(xué)習(xí)一邊調(diào)整而來俏拱,著實不易,撒花吕世。
同樣彰触,這個只是一個規(guī)則
執(zhí)行命令

bison --yacc -dv --defines=skl_language_parser.h --output=skl_language_parser.c skl_language_parser.y

這樣生成的skl_language_parser.h和skl_language_parser.c才是詞法解析器源碼。
當(dāng)然要看懂上述的內(nèi)容和知識命辖,也要花一番功夫况毅。

結(jié)語

做成一件事,沒有隨隨便便尔艇,既然做了尔许,就要達(dá)成初心

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市终娃,隨后出現(xiàn)的幾起案子味廊,更是在濱河造成了極大的恐慌,老刑警劉巖棠耕,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件余佛,死亡現(xiàn)場離奇詭異,居然都是意外死亡窍荧,警方通過查閱死者的電腦和手機辉巡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蕊退,“玉大人郊楣,你說我怎么就攤上這事憔恳。” “怎么了净蚤?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵钥组,是天一觀的道長。 經(jīng)常有香客問我今瀑,道長程梦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任放椰,我火速辦了婚禮作烟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘砾医。我一直安慰自己拿撩,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布如蚜。 她就那樣靜靜地躺著压恒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪错邦。 梳的紋絲不亂的頭發(fā)上探赫,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機與錄音撬呢,去河邊找鬼伦吠。 笑死,一個胖子當(dāng)著我的面吹牛魂拦,可吹牛的內(nèi)容都是我干的毛仪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼芯勘,長吁一口氣:“原來是場噩夢啊……” “哼箱靴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荷愕,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤衡怀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后安疗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抛杨,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年荐类,在試婚紗的時候發(fā)現(xiàn)自己被綠了蝶桶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡掉冶,死狀恐怖真竖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情厌小,我是刑警寧澤恢共,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站璧亚,受9級特大地震影響讨韭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜癣蟋,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一透硝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧疯搅,春花似錦濒生、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至礁蔗,卻和暖如春觉义,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浴井。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工晒骇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人磺浙。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓洪囤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親屠缭。 傳聞我的和親對象是個殘疾皇子箍鼓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容