1. 程式人生 > >編譯器之詞法分析c

編譯器之詞法分析c

我學編譯原理沒有多久,剛剛學到語義分析,所以我也算是菜鳥。。。 無意間看到了《自己動手寫編譯器、連結器》這本書,覺得實現一個編譯器才算是真正的入門。

本來我是沒有決心寫好一個c語言的編譯器的,因為c語言的詞法、語法等等有太多的內容,但是無奈曾經也就學習過c語言、c++、scheme(學了一點點就沒學了),

硬著頭皮去看書、敲程式碼,並且整理。我的意思就是選擇說選擇一門你熟悉的語言,然後學習之。不要三天打魚。寫一個編譯器不是想象中的那麼簡單,如果學習到了一半

就放棄了,那麼效果肯定不會太理想。我下面的程式碼參考了《自己動手寫編譯器、連結器》這本書,這也是我第一次寫c語言編譯器。但是我是用了c++實現,或許我的程式碼風格

很像c(那是因為我的水平不高),但也花了幾天的時間去學習。。。

或許還存在著一些錯誤,在等我我寫完語法分析等等之後才會發現。。所以說湊合著看吧。。畢竟我也是第一次寫這玩意

#ifndef Lexc___hpp

#define Lexc___hpp

#include <stdio.h>

#include <fstream>

#include <iostream>

#include <vector>

#include <cctype>

//類似於string的資料結構

struct

DynString

{

int     count;

int     capacity;           //capacity容量

char    *data;              //指標

};

//每一個data存放一個string

template <typename T>

struct DynArray

{

int     count;

int     capacity;

    T       *data;

};

struct TkWord

{

int             tkcode;                    

//單詞編碼

TkWord          *next;

std::string     spelling;

//   Sysbol          *sym_struct;      第六節才會講

};

enum e_TokenCode

{

/* 運算子及分隔符 */

    TK_PLUS,// + 加號

    TK_MINUS,// - 減號

    TK_STAR,// * 星號

    TK_DIVIDE,// / 除號

    TK_MOD,// % 求餘運算子

    TK_EQ,// == 等於號

    TK_NEQ,// != 不等於號

    TK_LT,// < 小於號

    TK_LEQ,// <= 小於等於號

    TK_GT,// > 大於號

    TK_GEQ,// >= 大於等於號

    TK_ASSIGN,// = 賦值運算子

    TK_POINTSTO,// -> 指向結構體成員運算子

    TK_DOT,// . 結構體成員運算子

    TK_AND,         // & 地址與運算子

    TK_OPENPA,// ( 左圓括號

    TK_CLOSEPA,// ) 右圓括號

    TK_OPENBR,// [ 左中括號

    TK_CLOSEBR,// ] 右圓括號

    TK_BEGIN,// { 左大括號

    TK_END,// } 右大括號

    TK_SEMICOLON,// ; 分號

    TK_COMMA,// , 逗號

    TK_ELLIPSIS,// ... 省略號

    TK_EOF,// 檔案結束符

/* 常量 */

    TK_CINT,// 整型常量

    TK_CCHAR,// 字元常量

    TK_CSTR,// 字串常量

/* 關鍵字 */

    KW_CHAR,// char關鍵字

    KW_SHORT,// short關鍵字

    KW_INT,// int關鍵字

    KW_VOID,// void關鍵字

    KW_STRUCT,// struct關鍵字

    KW_IF,// if關鍵字

    KW_ELSE,// else關鍵字

    KW_FOR,// for關鍵字

    KW_CONTINUE,// continue關鍵字

    KW_BREAK,// break關鍵字

    KW_RETURN,// return關鍵字

    KW_SIZEOF,// sizeof關鍵字

    KW_ALIGN,// __align關鍵字

    KW_CDECL,// __cdecl關鍵字 standard c call

    KW_STDCALL,     // __stdcall關鍵字 pascal c call

/* 識別符號 */

    TK_IDENT

};

class __DynString

{

public:

using dynstring = DynString;

class __DynArray;

char ch = 0;

    __DynString(): get_i(0)

    {

pstr = newdynstring;

pstr->data = newchar;

pstr->count = 0;

pstr->capacity = 0;

    }

void dynstring_init(int init)

    {

pstr->data = newchar[init];

pstr->count = 0;

pstr->capacity = init;

    }

void dynstring_free()

    {

if(pstr->data != nullptr)

        {

deletepstr->data;

// std::cout << "s\n";

        }

pstr->count = 0;

pstr->capacity = 0;

    }

void dynstring_reset()

    {

dynstring_free();

dynstring_init(8);

    }

void dynstring_realloc(int new_size)

    {

int capacity;

char *data;

        capacity = pstr->capacity;

while(capacity < new_size)

            capacity = capacity * 2;

        data = (char *)realloc(pstr->data, capacity);

pstr->capacity = capacity;

pstr->data = data;

    }

void dynstring_chcat(int ch)

    {

int count = pstr->count + 1;

if(count > pstr->capacity)

dynstring_realloc(count);

pstr->data[count - 1] = ch;

pstr->count = count;

    }

void dynstring_print()

    {

std::cout << pstr->data;

    }

char* getdata()

    {

char *ch;

        ch = pstr->data;

return ch;

    }

private:

int         get_i;                  //計數

dynstring   *pstr;            //指標

};

template<typename T>

class __DynArray

{

public:

using dynarray = DynArray<T>;

    __DynArray()

    {

parr = newdynarray;

parr->data = new T[4];

parr->count = 0;

parr->capacity = 4;

    }

void init(int init)

    {

parr = newdynarray;

parr->data = new T[init];

parr->count = 0;

parr->capacity = init;

    }

void dynarray_realloc(int new_size)

    {

int capacity;

        T   *data;

        capacity = parr->capacity;

while(capacity < new_size)

            capacity = capacity * 2;

        data = new T[capacity];

for(auto vt = 0; vt < parr->capacity; ++vt)

            data[vt] = parr->data[vt];

parr->capacity  = capacity;

parr->data = data;

    }

void dynarray_add(T data)

    {

int count;

        count = parr->count + 1;

if(count > parr->capacity)

dynarray_realloc(count);

parr->data[count - 1] = data;

parr->count = count;

    }

void dynarray_free()

    {

void **p;

for(p = parr->data; parr->count; ++p, --parr->count)

if(*p)

free(*p);

parr->data = nullptr;

    }

int dynarray_search(int key)

    {

int **p = (int**)parr->data;

for(int i = 0; i < parr->count; ++i, p++)

if(key == **p)

return i;

return -1;

    }

void dynarray_print()

    {

auto size = parr->count;

//  std::cout << size;

for(int i = 0; i < size; ++i)

std::cout << parr->data[i].spelling << " " ;

//.. std::cout << std::endl;

    }

int getint()

    {

int temp = parr->count;

return temp;

    }

TkWord getdata(int v)

    {

TkWord tk = parr->data[v];

return tk;

    }

private:

dynarray        *parr;

};

template <typename T>

class __TkWord

{

public:

using tkword = TkWord;

__DynArray<T>  tktable;

    __TkWord<T>(): token(0)

    {

tp = newtkword;

tp->tkcode = 0;

tp->spelling = "\0";

tp->next = 0;

    }

tkword *tkword_direct_insert()

    {

int keyno = elf_hash(tp->spelling);

tktable.dynarray_add(*tp);

tp->next = tk_hashtable[keyno];

tk_hashtable[keyno] = tp;

returntp;

    }

tkword *tkword_find(char *p, int keyno)

    {

//tkword *tp = nullptr;

auto tp1 = tk_hashtable[keyno];

if(tp1 == NULL)

returnnullptr;

returntp;

    }

tkword *tkword_insert(char *p)

    {

int keyno = elf_hash(p);

tp = tkword_find(p, keyno);

if(tp == nullptr)

        {

size_t length = strlen(p);

tp = newtkword[length + 1];

tp->next = tk_hashtable[keyno];

tk_hashtable[keyno] = tp;

tktable.dynarray_add(*tp);

tp->tkcode = tktable.getint() - 1;

char *s = (char *)tp + sizeof(tkword);

for(auto end = p + length; p < end;)

                *s++ = *p++;

            *s = (char)'\0';

        }

returntp;

    }

/*

     void *Lex::mallocz(int size)

     {

     void *ptr;

     ptr = mallocz(size);

相關推薦

編譯器詞法分析c

我學編譯原理沒有多久,剛剛學到語義分析,所以我也算是菜鳥。。。 無意間看到了《自己動手寫編譯器、連結器》這本書,覺得實現一個編譯器才算是真正的入門。 本來我是沒有決心寫好一個c語言的編譯器的,因為c語言的詞法、語法等等有太多的內容,但是無奈曾經也就學習過c語言、

C#詞法分析器詞法分析的使用詳解(一)

雖然文章的標題是詞法分析,但首先還是要從編譯原理說開來。編譯原理應該很多人都聽說過,雖然不一定會有多麼瞭解。 簡單的說,編譯原理就是研究如何進行編譯——也就如何從程式碼(*.cs 檔案)轉換為計算機可以執行的程式(*.exe 檔案)。當然也有些語言如 JavaScrip

編譯器DIY——詞法分析

在上一篇文章中已經介紹了讀檔案的操作,那麼這一篇文章中將會仔細解釋詞法分析。 在原始檔中解析出的單詞流必須識別為保留字,識別符號,常量,操作符和界符五大類 1.顯然我們需要列舉出所有的保留字,而這裡與保留字相似的那麼就是識別符號,在C語言中,保留字都是以小寫字母開頭,而且其

編譯原理實驗(一)詞法分析

詞法分析 (1)參考附錄1設計一個簡單語言的詞法分析程式,要求能夠處理註釋、換行回車、部分複合運算子(如>=)。 (2)設計並實現含多條簡單賦值語句的語法分析程式,要求有一定的出錯提示與錯誤恢復功能。    (參考附錄2) 附錄1: 例C源程式段: ma

編譯原理實驗詞法分析

內容有更新哦~~~ 能識別小數,科學記數法表示的數,負數亦可。 不多解釋,程式碼先上: #include <cstdio> #include <iostream> #include <string> #include <cstr

編譯原理詞法分析、語法分析、語義分析

詞法分析(Lexical analysis或Scanning)和詞法分析程式(Lexical analyzer或Scanner)   詞法分析階段是編譯過程的第一個階段。這個階段的任務是從左到右一個字元一個字元地讀入源程式,即對構成源程式的字元流進行掃描然後根據構詞規則識別單詞(也稱單詞符號或符號)。詞法

java編譯器原始碼分析詞法分析器

java編譯器是什麼? 編譯簡單理解就是一種高階語言到另一種低階語言的翻譯過程;而執行這個過程的主體稱為編譯器。尋常所說的編譯器是指把組合語言轉變成機器語言,也稱目的碼,即CPU指令集。組合語言是一種比機器語言對人友好的語言,但不同機器硬體構造不一樣,驅動機器的

結對編程--C語言子程序詞法分析

字符串 之前 info default 管理 問題 min div == 一、問題描述 C語言小子集表的定義 2.設計單詞屬性值,各類表格(表示標識符表、常量表),單詞符號及機內表示,采用標準輸入和輸出的方式。程序從鍵盤接收代碼,遇到代碼結束符“#”時結束,並將

python學習路 jJavaScript詞法分析

優先 覆蓋 bject AR 又是 調用函數 運行 () class 詞法分析步驟 JavaScript在運行前會有一個類似預編譯的過程這個過程就是我們所說的詞法分析。這個詞法分析的步驟 分析參數 再分析變量的聲明 分析函數說明 列子: function func(ag

C# 詞法分析器(一)詞法分析介紹

art 優化 不一定 clr gen 多個 scan 原理 輸入緩沖 系列導航 (一)詞法分析介紹 (二)輸入緩沖和代碼定位 (三)正則表達式 (四)構造 NFA (五)轉換 DFA (六)構造詞法分析器 (七)總結 雖然文章的標題是詞法分析,但

GCC編譯器原理(三)------編譯原理三:編譯過程(2-2)---編譯語法分析

tails 需要 表達式 一個數 就是 out 和數 margin 操作符 2.2 語法分析 語法分析器(Grammar Parser)將對由掃描器產生的記號進行語法分析,從而產生語法樹(Syntax Tree)。整個分析過程采用了上下文無關語法(Context-free

資料結構連結串列C語言實現以及使用場景分析

連結串列是資料結構中比較基礎也是比較重要的型別之一,那麼有了陣列,為什麼我們還需要連結串列呢!或者說設計連結串列這種資料結構的初衷在哪裡? 這是因為,在我們使用陣列的時候,需要預先設定目標群體的個數,也即陣列容量的大小,然而實時情況下我們目標的個數我們是不確定的,因此我們總是要把陣列的容量設定的

C語言--詞法分析程式

小C語言文法  1. <程式>→(){<宣告序列><語句序列>} 2. <宣告序列>→<宣告序列><宣告語句>|<宣告語句>|<空> 3. <宣告語句>→<識別符

編譯原理 小C語言--詞法分析程式

Problem Description 小C語言文法  1. <程式>→(){<宣告序列><語句序列>} 2. <宣告序列>→<宣告序列><宣告語句>|<宣告語句>|<空> 3.

LCC編譯器的源程式分析 1 C編譯器的目標

先從簡單的目標來分析這個大規模的 C 編譯器,畢竟它的功能比較複雜,並且源程式的行數也是非常多的。因此,把簡單的目標定出來,然後再分析它,這樣才會有的放矢。接著再跟著編譯執行的主線來分析它的源程式。下面先看一下簡單的 C 例子,如下:   #0

JAVA實現一個簡單的代數運算語言編譯器(二)--詞法分析準備

上一篇文章主要介紹了這個代數運算編譯器的起因,這一篇我們就來開始寫這個專案。 首先我們需要先設定一些系統的基礎類如系統符號類,保留字類、錯誤提示資訊類、自定義異常、輸入讀取類等,下面簡單地說一下這幾個類。 系統符號類: package com.liu.system; /

編譯原理實驗報告一:PL0語言編譯器分析(PL0,詞法分析,語法分析,中間程式碼生成)

實驗報告一:PL0語言編譯器分析一、實驗目的       通過閱讀與解析一個實際編譯器(PL/0語言編譯器)的原始碼, 加深對編譯階段(包括詞法分析、語法分析、語義分析、中間程式碼生成等)和編譯系統軟體結構的理解,並達到提高學習興趣的目的。二、實驗要求(1)   要求掌握基本

編譯原理 實驗一 詞法分析預處理

import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public cl

stout程式碼分析十:c++11move和forward

  stout中大量使用了c++11的特性,而c++11中move和forward大概是最神奇的特性了. 左值和右值的區別 int a = 0; // a是左值,0是右值 int b = rand(); // b是左值,rand()是右值   直觀理解:左值在等號左邊,右值在等號

資料庫中介軟體 Sharding-JDBC 原始碼分析 —— SQL 解析(一)詞法解析

本文主要基於 Sharding-JDBC 1.5.0 正式版 ������關注微信公眾號:【芋道原始碼】有福利: 1. RocketMQ / MyCAT / Sharding-JDBC 所有原始碼分析文章列表 2. Roc