日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

简单的C语言编译器--词法分析器

發(fā)布時間:2024/6/21 综合教程 36 生活家
生活随笔 收集整理的這篇文章主要介紹了 简单的C语言编译器--词法分析器 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. 定義詞法單元Tag

??首先要將可能出現(xiàn)的詞進(jìn)行分類,可以有不同的分類方式。如多符一類:將所有逗號、分號、括號等都?xì)w為一類,或者一符一類,將一個符號歸為一類。我這里采用的是一符一類的方式。C代碼如下:

    #ifndef TAG_H
    #define TAG_H
    
    namespace Tag {
    	//保留字
    	const int
    		INT = 1, BOOL = 2, MAIN = 3, IF = 4,
    		ELSE = 5, FOR = 6, WHILE = 7, FALSE = 8,
    		BREAK = 9, RETURN = 10, TRUE = 11 ;	
    
    	//運(yùn)算符
    	const int
    		NOT = 20, NE = 21, AUTOMINUS =22, MINUS = 23,
    		AUTOADD = 24, ADD = 25, OR = 26, 
    		AND = 27, MUTIPLY = 28, DIVIDE = 29, MOD = 30,
    		EQ = 31, ASSIN = 32, GE = 33, GT = 34,
    		LE = 35, LS = 36;
    
    	//分界符
    	const int 
    		COMMA = 40, SEMICOLON = 41, LLBRACKET = 42,
    		RLBRACKET = 43, LMBRACKET = 44, RMBRACKET = 45,
    		LGBRACKET = 46, RGBRACKET = 47;
    
    	//整數(shù)常數(shù)
    	const int NUM = 50;
    
    	//標(biāo)識符
    	const int ID = 60;
    
    	//錯誤
    	const int ERROR = 404;
    
    	//空
    	const int  EMPTY = 70;
    
    }

#endif

2. 具體步驟

一個一個字符地掃描測試代碼,忽略空白字符,遇到回車時,記錄行數(shù)加1
要進(jìn)行區(qū)分標(biāo)識符(即普通變量名字)和保留字
因?yàn)閷?biāo)識符和常數(shù)都guiwe各自歸為一類,所以要有算法能夠識別出一整個常數(shù)和完整的標(biāo)識符
加入適當(dāng)?shù)姆欠ㄔ~檢測

3. 設(shè)計詞法分析類

??設(shè)計一個詞法分析器,當(dāng)然要包括如何存儲一個詞法單元,如何掃描(scan)測試代碼等,直接上代碼:

myLexer.h

    #ifndef MYLEXER_H
    #define MYLEXER_H
    
    #include <fstream>
    #include <string>
    #include <unordered_map>
    #include "tag.h"
    
    
    /*
     * 主要是定義基本的詞法單元類,
     * 聲明了詞法分析類
     */
    
    //存儲詞法單元
    class Word {
    	public:
    		Word() = default;
    		Word(std::string s, int t) : lexeme(s), tag(t) {};
    		std::string getLexeme() { return lexeme; };
    		int getTag() { return tag; }
    		void setTag(int t) { tag = t; }
    		void setLexeme(std::string s) { lexeme = s; }
    	private:
    		std::string lexeme;
    		int tag;
    };
    
    //詞法分析器類
    class Lexer {
    	public:
    		Lexer();
    		void reserve(Word w);
    		bool readnext(char c, std::ifstream &in);
    		Word scan(std::ifstream &in);
    		int getLine() { return line; }
    	private:
    		char peek;
    		std::unordered_map<std::string, Word> words;
    		int line;
    };
    
    
    #endif

myLexer.cpp

    #include <iostream>
    #include <cctype>
    #include <sstream>
    #include "myLexer.h"
    
    void Lexer::reserve(Word w) {
    	words.insert({w.getLexeme(), w});
    }
    
    Lexer::Lexer() {
    	//存入保留字,為了區(qū)分標(biāo)識符
    	reserve( Word("int", Tag::INT) );
    	reserve( Word("bool", Tag::BOOL) );
    	reserve( Word("main", Tag::MAIN) );
    	reserve( Word("if", Tag::IF) );
    	reserve( Word("else", Tag::ELSE) );
    	reserve( Word("for", Tag::FOR) );
    	reserve( Word("while", Tag::WHILE) );
    	reserve( Word("break", Tag::BREAK) );
    	reserve( Word("return", Tag::RETURN) );
    	reserve( Word("true", Tag::TRUE) );
    	reserve( Word("false", Tag::FALSE) );
    	
    	peek = ' ';
    	line = 1;
    
    }
    
    //方便處理像>=,++等這些兩個字符連在一起的運(yùn)算符
    bool Lexer::readnext(char c, std::ifstream &in) {
    	in >> peek;
    	if( peek != c)
    		return false;
    	peek = ' ';
    	return true;
    }
    
    
    Word Lexer::scan(std::ifstream &in) {
    	//跳過空白符
    	while(!in.eof()) {
    		if(peek == ' ' || peek == '	') {
    			in >> peek;
    			continue;
    		}
    		else if(peek == '
')
    			++line;
    		else
    			break;
    		in >> peek;
    	}
    
    	//處理分界符、運(yùn)算符等
    	switch(peek) {
    		case '!':
    			if(readnext('=', in))
    				return Word("!=", Tag::NE);
    			else
    				return Word("!", Tag::NOT);
    		case '-':
    			if(readnext('-', in))
    				return Word("--", Tag::AUTOMINUS);
    			else
    				return Word("-", Tag::MINUS);
    		case '+':
    			if(readnext('+', in)) 
    				return Word("++", Tag::AUTOADD);
    			else
    				return Word("+", Tag::ADD);
    		case '|':
    			if(readnext('|', in)) 
    				return Word("||", Tag::OR);
    			else
    				return Word("error", Tag::ERROR);
    		case '&':
    			if(readnext('&', in))
    				return Word("&&", Tag::AND);
    			else
    				return Word("error", Tag::ERROR);
    		case '*':
    			in >> peek;
    			return Word("*", Tag::MUTIPLY);
    		case '/':
    			in >> peek;
    			return Word("/", Tag::DIVIDE);
    		case '%':
    			in >> peek;
    			return Word("%", Tag::MOD);
    		case '=':
    			if(readnext('=', in))
    				return Word("==", Tag::EQ);
    			else
    				return Word("=", Tag::ASSIN);
    		case '>':
    			if(readnext('=', in))
    				return Word(">=", Tag::GE);
    			else
    				return Word(">", Tag::GT);
    		case '<':
    			if(readnext('=', in))
    				return Word("<=", Tag::LE);
    			else
    				return Word("<", Tag::LS);
    		case ',':
    			in >> peek;
    			return Word(",", Tag::COMMA);
    		case ';':
    			in >> peek;
    			return Word(";", Tag::SEMICOLON);
    		case '(':
    			in >> peek;
    			return Word("(", Tag::LLBRACKET);
    		case ')':
    			in >> peek;
    			return Word(")", Tag::RLBRACKET);
    		case '[':
    			in >> peek;
    			return Word("[", Tag::LMBRACKET);
    		case ']':
    			in >> peek;
    			return Word("]", Tag::RMBRACKET);
    		case '{':
    			in >> peek;
    			return Word("{", Tag::LGBRACKET);
    		case '}':
    			in >> peek;
    			return Word("}", Tag::RGBRACKET);
    	}
    	
    	//處理常數(shù)
    	if(isdigit(peek)) {
    		int v = 0;
    		do {
    			v = 10*v + peek - 48;
    			in >> peek;
    		} while(isdigit(peek));
    		if(peek != '.')
    			return Word(std::to_string(v), Tag::NUM);
    	}	
    
    
    	//處理標(biāo)識符
    	if(isalpha(peek)) {
    		std::ostringstream b;		
    		do {
    			b << peek;
    			in >> peek;
    		} while(isalnum(peek) || peek == '_');
    
    		std::string tmp = b.str();
    
    		//判斷是否為保留字
    		if(words.find(tmp) != words.end()) 
    			return words[tmp];
    		else
    			return Word(tmp, Tag::ID);
    	}
    	if(peek != ' ' && peek != '	' && peek != '
')	
    		return Word("error", Tag::ERROR);
    	return Word("empty", Tag::EMPTY);
    }

??設(shè)計完成后,自己寫一個Main函數(shù),在while循環(huán)中調(diào)用scan函數(shù),每次打印出Word內(nèi)容,就能夠得到

總結(jié)

以上是生活随笔為你收集整理的简单的C语言编译器--词法分析器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。