`
daojin
  • 浏览: 690210 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

自己动手写C语言编译器(3)

 
阅读更多

词法分析器部分完成。

支持:

1.支持单词分割

2.支持数字类型

3.支持字符串

4.支持换行

6.支持注释

 

不支持:

1.不支持关键字

2.不支持变量。

3.不支持关键字。

4.不支操作符。

 

偶没有被那些个编译原理课程所吓倒。。。。。真的勇士,只管前行!

 

 

 

#ifndef _ISTREAMTOKENIZER_H_
#define _ISTREAMTOKENIZER_H_

#include <limits.h>
#include <string>
#include <istream>
#include <vector>
#define _COUNT_OF(a) (sizeof(a)/sizeof(a[0]))

class IstreamTokenizer 
{
    private:
		
		/**
		* The next character to be considered by the nextToken method.  May also
		* be NEED_CHAR to indicate that a new character should be read, or SKIP_LF
		* to indicate that a new character should be read and, if it is a '\n'
		* character, it should be discarded and a second new character should be
		* read.
		*/
		static const int SKIP_LF;
		static const int NEED_CHAR;

		//字符类型
		static const unsigned char CT_WHITESPACE;
		static const unsigned char CT_DIGIT;
		static const unsigned char CT_ALPHA;
		static const unsigned char CT_QUOTE;
		static const unsigned char CT_COMMENT;
	
	public:
		//token类型
		static const int TT_EOF;
		static const int TT_EOL;
		static const int TT_NUMBER;
		static const int TT_WORD;
		static const int TT_NOTHING;
	
	
	private:
		std::istream& input;

		std::vector<char> buf;

		int peekc;

        bool pushedBack;
		
		bool forceLower;

		int LINENO;
		
		bool eolIsSignificantP;
		
		bool slashSlashCommentsP;
		
		bool slashStarCommentsP;
		
		unsigned char ctype[256];

	public:
		std::string sval;

		double nval;
		
		int ttype;
	
	private:
		void init() 
		{
			wordChars('a', 'z');
			wordChars('A', 'Z');
			wordChars(128 + 32, 255);
			whitespaceChars(0, ' ');
			commentChar('/');
			quoteChar('"');
			quoteChar('\'');
			parseNumbers();
		}

    public:
		IstreamTokenizer(std::istream& is): input(is), peekc(NEED_CHAR)
		{
			init();
		}
		
		void resetSyntax() 
		{
			for (int i = _COUNT_OF(ctype); --i >= 0;)
				ctype[i] = 0;
		}
		
		
		void wordChars(int low, int hi) 
		{
			if (low < 0)
				low = 0;
			if (hi >= _COUNT_OF(ctype))
				hi = _COUNT_OF(ctype) - 1;
			while (low <= hi)
				ctype[low++] |= CT_ALPHA;
		}
		
		
		void whitespaceChars(int low, int hi) 
		{
			if (low < 0)
				low = 0;
			if (hi >= _COUNT_OF(ctype))
				hi = _COUNT_OF(ctype) - 1;
			while (low <= hi)
				ctype[low++] = CT_WHITESPACE;
		}
		
		
		void ordinaryChars(int low, int hi) 
		{
			if (low < 0)
				low = 0;
			if (hi >= _COUNT_OF(ctype))
				hi = _COUNT_OF(ctype) - 1;
			while (low <= hi)
				ctype[low++] = 0;
		}
		

		void ordinaryChar(int ch) 
		{
			if (ch >= 0 && ch < _COUNT_OF(ctype))
				ctype[ch] = 0;
		}
		
		
		void commentChar(int ch) 
		{
			if (ch >= 0 && ch < _COUNT_OF(ctype))
				ctype[ch] = CT_COMMENT;
		}
		
		
		void quoteChar(int ch) 
		{
			if (ch >= 0 && ch < _COUNT_OF(ctype))
				ctype[ch] = CT_QUOTE;
		}
		
		
		void parseNumbers() 
		{
			for (int i = '0'; i <= '9'; i++)
				ctype[i] |= CT_DIGIT;
				ctype['.'] |= CT_DIGIT;
				ctype['-'] |= CT_DIGIT;
		}
		
		/**
		* Determines whether or not ends of line are treated as tokens.
		* If the flag argument is true, this tokenizer treats end of lines
		* as tokens; the <code>nextToken</code> method returns
		* <code>TT_EOL</code> and also sets the <code>ttype</code> field to
		* this value when an end of line is read.
		* <p>
		* A line is a sequence of characters ending with either a
		* carriage-return character (<code>'&#92;r'</code>) or a newline
		* character (<code>'&#92;n'</code>). In addition, a carriage-return
		* character followed immediately by a newline character is treated
		* as a single end-of-line token.
		* <p>
		* If the <code>flag</code> is false, end-of-line characters are
		* treated as white space and serve only to separate tokens.
		*
		* @param   flag   <code>true</code> indicates that end-of-line characters
		*                 are separate tokens; <code>false</code> indicates that
		*                 end-of-line characters are white space.
		* @see     java.io.StreamTokenizer#nextToken()
		* @see     java.io.StreamTokenizer#ttype
		* @see     java.io.StreamTokenizer#TT_EOL
		*/
		void eolIsSignificant(bool flag) 
		{
			eolIsSignificantP = flag;
		}
		
		
		void slashStarComments(bool flag) 
		{
			slashStarCommentsP = flag;
		}
		
		
		void slashSlashComments(bool flag) 
		{
			slashSlashCommentsP = flag;
		}
		
		
		void lowerCaseMode(bool fl) 
		{
			forceLower = fl;
		}
		
		/** Read the next character */
		private:
			int read()  
			{
			return input.get();	
		}
		
	
		int nextToken() {
			if (pushedBack) {
				pushedBack = false;
				return ttype;
			}

			unsigned char* ct = ctype;

			int c = peekc;
			if (c < 0)
				c = NEED_CHAR;
			if (c == SKIP_LF) {
				c = read();
				if (c < 0)
					return ttype = TT_EOF;
				if (c == '\n')
					c = NEED_CHAR;
			}
			if (c == NEED_CHAR) {
				c = read();
				if (c < 0)
					return ttype = TT_EOF;
			}
			ttype = c;		/* Just to be safe */
			
							/* Set peekc so that the next invocation of nextToken will read
							* another character unless peekc is reset in this invocation
			*/
			peekc = NEED_CHAR;
			
			int ctype = c < 256 ? ct[c] : CT_ALPHA;
			while ((ctype & CT_WHITESPACE) != 0) {
				if (c == '\r') {
					LINENO++;
					if (eolIsSignificantP) 
					{
						//end of line 作为结束的标识。
						peekc = SKIP_LF;
						return ttype = TT_EOL;
					}
					c = read();
					if (c == '\n')
						c = read();
				} else {
					if (c == '\n') {
						LINENO++;
						if (eolIsSignificantP) {
							//end of line 作为结束的标识。
							return ttype = TT_EOL;
						}
					}
					c = read();
				}
				if (c < 0)
					return ttype = TT_EOF;
				ctype = c < 256 ? ct[c] : CT_ALPHA;
			}
			
			if ((ctype & CT_DIGIT) != 0) {
				bool neg = false;
				if (c == '-') {
					c = read();
					if (c != '.' && (c < '0' || c > '9')) {
						peekc = c;
						return ttype = '-';
					}
					neg = true;
				}
				double v = 0;
				int decexp = 0;
				int seendot = 0;
				while (true) {
					if (c == '.' && seendot == 0)
						seendot = 1;
					else if ('0' <= c && c <= '9') {
						v = v * 10 + (c - '0');
						decexp += seendot;
					} else
						break;
					c = read();
				}
				peekc = c;
				if (decexp != 0) {
					double denom = 10;
					decexp--;
					while (decexp > 0) {
						denom *= 10;
						decexp--;
					}
					/* Do one division of a likely-to-be-more-accurate number */
					v = v / denom;
				}
				nval = neg ? -v : v;
				return ttype = TT_NUMBER;
			}
			
			if ((ctype & CT_ALPHA) != 0) {
				int i = 0;
				do {
					if (i >= buf.size()) {
						buf.resize(buf.size()*2);
					}
					buf[i++] = (char) c;
					c = read();
					ctype = c < 0 ? CT_WHITESPACE : c < 256 ? ct[c] : CT_ALPHA;
				} while ((ctype & (CT_ALPHA | CT_DIGIT)) != 0);
				
				peekc = c;

				sval.resize(i, 0);

				std::copy(buf.begin(), buf.end(), sval.begin());

				return ttype = TT_WORD;
			}
			
			if ((ctype & CT_QUOTE) != 0) {
				ttype = c;
				int i = 0;
				int d = read();
				while (d >= 0 && d != ttype && d != '\n' && d != '\r') 
				{
					if (d == '\\') {
						c = read();
						int first = c;   /* To allow \377, but not \477 */
						if (c >= '0' && c <= '7') {
							c = c - '0';
							int c2 = read();
							if ('0' <= c2 && c2 <= '7') {
								c = (c << 3) + (c2 - '0');
								c2 = read();
								if ('0' <= c2 && c2 <= '7' && first <= '3') {
									c = (c << 3) + (c2 - '0');
									d = read();
								} else
									d = c2;
							} else
								d = c2;
						} else {
							switch (c) {
							case 'a':
								c = 0x7;
								break;
							case 'b':
								c = '\b';
								break;
							case 'f':
								c = 0xC;
								break;
							case 'n':
								c = '\n';
								break;
							case 'r':
								c = '\r';
								break;
							case 't':
								c = '\t';
								break;
							case 'v':
								c = 0xB;
								break;
							}
							d = read();
						}
					} else {
						c = d;
						d = read();
					}
					if (i >= buf.size()) {
						buf.resize(buf.size()*2);
					}
					buf[i++] = (char)c;
				}
				
				/* If we broke out of the loop because we found a matching quote
				* character then arrange to read a new character next time
				* around; otherwise, save the character.
				*/
				peekc = (d == ttype) ? NEED_CHAR : d;
				
				buf.resize(i);
				std::copy(buf.begin(), buf.end(), sval.begin());

				return ttype;
			}
			
			if (c == '/' && (slashSlashCommentsP || slashStarCommentsP)) {
				c = read();
				if (c == '*' && slashStarCommentsP) {
					int prevc = 0;
					while ((c = read()) != '/' || prevc != '*') {
						if (c == '\r') {
							LINENO++;
							c = read();
							if (c == '\n') {
								c = read();
							}
						} else {
							if (c == '\n') {
								LINENO++;
								c = read();
							}
						}
						if (c < 0)
							return ttype = TT_EOF;
						prevc = c;
					}
					return nextToken();
				} else if (c == '/' && slashSlashCommentsP) {
					while ((c = read()) != '\n' && c != '\r' && c >= 0);
					peekc = c;
					return nextToken();
				} else {
					/* Now see if it is still a single line comment */
					if ((ct['/'] & CT_COMMENT) != 0) {
						while ((c = read()) != '\n' && c != '\r' && c >= 0);
						peekc = c;
						return nextToken();
					} else {
						peekc = c;
						return ttype = '/';
					}
				}
			}
			
			if ((ctype & CT_COMMENT) != 0) {
				while ((c = read()) != '\n' && c != '\r' && c >= 0);
				peekc = c;
				return nextToken();
			}
			
			return ttype = c;
    }
	
    
     void pushBack() {
        if (ttype != TT_NOTHING)
			pushedBack = true;
    }

     int lineno() {
		return LINENO;
    }
	
     std::string toString();
	
};

const unsigned char IstreamTokenizer::CT_WHITESPACE = 1;

const unsigned char IstreamTokenizer::CT_DIGIT = 2;

const unsigned char IstreamTokenizer::CT_ALPHA = 4;

const unsigned char IstreamTokenizer::CT_QUOTE = 8;

const unsigned char IstreamTokenizer::CT_COMMENT = 16;

const int IstreamTokenizer::NEED_CHAR = INT_MAX;
 
const int IstreamTokenizer::SKIP_LF = INT_MAX - 1;

#endif
 
4
15
分享到:
评论

相关推荐

    c语言编译器

    学习和理解这些源代码可以帮助开发者深入理解编译器的工作机制,甚至动手编写自己的编译器或解释器。 编写一个C语言编译器是一项复杂但极富挑战性的任务,涉及到编译原理、数据结构和算法等多个领域的知识。初学者...

    自己动手写编译器、链接器_编译器_

    本书讲述了一个真实编译器的开发过程源语言是以C语言为蓝本进行适当简化定义的一门新语言称之为SC语言(简化的C语言)目标语言是大家熟悉的Intelx86机器语言。在本书中读者将看到从 SC语言定义到SCC编译器开发的完整...

    一款用C语言写的C语言编译器。.zip

    标题中的“一款用C语言写的C语言编译器”指的是使用C语言开发的源代码,用于编译其他C语言程序的工具。C语言编译器是将人类可读的C语言源代码转换为计算机可执行的机器代码的关键软件。这个项目可能是为了教学目的,...

    一整套的c语言编译器的文档和代码资源

    这一资源集合旨在帮助用户深入理解编译器的工作原理,以及如何构建自己的C语言编译器。 【描述】:“一整套的c语言编译器的文档和代码资源”不仅包括了详尽的理论文档,也包含了实际的源代码,这对于学习编译原理...

    cpp-9cc一个很小的C语言编译器是8cc编译器的继承者

    这些知识对于深入理解计算机系统、提高编程技能,甚至自己动手编写编译器都大有裨益。 此外,了解9cc这样的小型编译器也有助于开发者在实际项目中优化性能。例如,对于特定场景下的嵌入式开发或者需要快速编译的...

    C语言写的一个编译器源码

    对于这个C语言编译器,生成的可能是与C语言兼容的目标代码,便于进一步的链接和执行。 这个“伪编译器”可能并未实现完整的编译器功能,例如优化和错误处理。但它的价值在于提供了一个简化的编译过程模型,帮助初学...

    动手写一个C语言编译器

    动手编写一个C语言编译器是一项挑战性的任务,但也是一个深入了解计算机工作原理的绝佳途径。编译器将高级语言转化为机器可执行的指令,涉及语言学、计算机科学和软件工程等多个领域。以下是一些关键的知识点: 1. ...

    一个最简的C语言编译器.zip

    《构建最简C语言编译器的探索与实践》 C语言是一种强大的、广泛应用的编程语言,它的简洁性、灵活性和高效性使得它在软件开发领域占有重要地位。然而,你知道C语言是如何被计算机理解并执行的吗?答案就是通过...

    简单的类C语言编译器的实现-电子商城例子

    在哈工大的编译原理课程设计...总之,"简单的类C语言编译器的实现-电子商城例子" 是一个综合性的实践项目,涵盖了编译原理的多个重要方面,并将其应用于实际问题中,对于提高学生的理论知识和动手能力有着显著的帮助。

    简单C语言编译器(编译原理).pdf

    《简单C语言编译器(编译原理)》是一份关于编译技术的文档,它主要探讨了如何构建一个简单的C语言编译器。编译器是将高级编程语言(如C语言)转换为机器可执行代码的软件,这个过程涉及多个阶段,包括词法分析、语法...

    C语言文本编译器源代码

    通过研究这个C语言编译器的源代码,初学者可以了解到编译器内部的运作机制,并学习如何使用C语言实现这些功能。这不仅有助于提升编程技能,还能加深对计算机系统底层的理解。 此外,项目中的源代码提供了一个很好的...

    自己动手打造C语言IDE源码

    "自己动手打造C语言IDE源码" 这个标题表明这是一个关于创建一个集成开发环境(IDE)的项目,专为C语言设计。IDE是程序员编写、调试和运行程序的软件平台,它通常包含代码编辑器、编译器、调试器等组件。在这个项目中...

    基于Vue.js的简易C语言编译器 [ 编译原理课程设计 ].zip

    这些实践环节有助于提高学生的动手能力和解决问题的能力,使他们更好地将理论知识应用于实际项目中。 综上所述,C语言课程设计具有基础性强、可移植性好、效率高、结构清晰、资源丰富和实践性强等优点。通过C语言的...

    一个简易c语言的编译器源码

    总结来说,这个简易C语言编译器项目为学习编译原理提供了一个实践平台。通过研究它的源代码,开发者可以理解编译器如何将高级语言翻译为机器语言,从而提升编程和软件工程的技能。同时,这个项目也鼓励动手实践,对...

    2023春季学期 北京邮电大学 编译原理与技术课程设计 Pascal-S到C语言编译器.zip

    这些实践环节有助于提高学生的动手能力和解决问题的能力,使他们更好地将理论知识应用于实际项目中。 综上所述,C语言课程设计具有基础性强、可移植性好、效率高、结构清晰、资源丰富和实践性强等优点。通过C语言的...

    C语言简化编译器前端 编译原理 LR1

    同时,提供的"Compiler"文件可能包含了编译器的源代码,通过阅读和研究这些代码,可以深入了解编译器的工作原理,并动手进行调试和改进,这对于提升编程和系统设计能力非常有益。 总的来说,这个项目旨在让开发者...

    编译原理课程设计,实现简易类C语言编译器,包括词法分析、语法分析、语义分析、翻译与简单优化.zip

    这些实践环节有助于提高学生的动手能力和解决问题的能力,使他们更好地将理论知识应用于实际项目中。 综上所述,C语言课程设计具有基础性强、可移植性好、效率高、结构清晰、资源丰富和实践性强等优点。通过C语言的...

    自己动手写CPU.rar

    在本项目中,"自己动手写CPU.rar" 是一个压缩包,其中包含了关于设计和实现CPU的源代码和相关资料。这个项目的核心是利用硬件描述语言Verilog进行CPU的开发,这是一种广泛应用于数字逻辑设计的语言,特别适用于创建...

    编译原理C语言小子集的编译器

    基于C++的C语言小子集编译器实现,包含了词法分析、语法分析、语义分析、中间代码生成等,从中理解编译程序的构造原理,掌握编译程序的构造方法与技术。通过实习,既加深对编译原理基础理论的理解,又提高动手能力,...

    plo编译器 c语言

    对于想要深入学习PLO编译器工作原理或者想要自己动手实现一个简单编译器的人来说,这是一个宝贵的资源。 总的来说,PLO编译器为初学者提供了一个学习编程的友好环境,而其C语言的实现则保证了编译器的效率和兼容性...

Global site tag (gtag.js) - Google Analytics