`
RednaxelaFX
  • 浏览: 3039744 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

跟语法搏斗……

阅读更多
以前一直听别人说写语法是件极其烧脑细胞的事,但是以前没自己写过没什么实感。这回可是好好体会了一次。

因为自顶而下的递归下降parser比较符合人的思维顺序,而相对来说LR系的shift-reduce冲突可能很难找到根源,所以这次在写语法的时候用ANTLR来帮忙了。具体来说是靠ANTLRWorks的编辑器/解释器/调试器来帮忙写出一个能正确解析我想使用的语法构造的LL(*)语法,然后再从这个语法出发来写比较正式的语法,大概还是会回归LALR(1)吧。我还是很想用Irony的。

问题是在不熟悉ANTLR的情况下,即便是递归下降也一样RP多多。我已经试了数不清多少次瞪着解释器里出现的那NoViableAltException发呆了。而且真的出现NoViableAltException,或者别的RecognitionException时,在ANTLRWorks能看到的信息还是觉得太少了。
可能是我现在还不太熟悉ANTLRWorks里的调试器的用法,总觉得真的要出错的时候,就在关键的那一步,一按step就出来一堆decision然后就error了,脑子完全没跟上啊。

结果还是靠把lexer和parser生成出来之后扔到Eclipse里慢慢调试才明白发生了什么事。不过想来也是,假如这时面对的是LR系的parser的话恐怕更郁闷了。
在调试的时候,基本上就是从自己的parser类跳到CommonTokenStream.LA(int)里,继续跳入CommonTokenStream.LT(int),CommonTokenStream.fillBuffer(),这里会跳入自己的lexer里的nextToken()。我碰到的好几个问题都是在lexer里出现的,刚开始跟是在CommonTokenStream.fillBuffer()里跟,等那个while循环慢慢把token吃进来然后在tokens这个ArrayList里看每个token的type看看对不对。实际上直接在自己的lexer里设断点也应该能行吧。

嘛,我是太不熟悉这玩意了。出现左递归还好办,但很多错误在ANTLRWorks的grammar check里都不会说出来;它也不知道你是不是故意那样写的嘛。我一开始肯定是昏了,居然没想起一个lexeme只能对应于一个token type。然后满怀希望要让"="既属于EQ又属于AssignmentOperator。傻了嗯。

ANTLR会为在语法规则里出现的所有字面量生成匿名的token type,看上去就像T10、T32之类的。为了让生成的代码好读一点,也应该用赋予了名字的词法规则来指定那些字面量,像是左括号"(",右括号")"之类。当希望某个lexeme本身就以一个独立的token type出现而不与其它lexeme混在一起(例如说"="与"+="要有不同的token type)时,这个词法规则就不能有fragment修饰符。

昨晚开始从头琢磨了一个语法出来。现在还相当的初步和粗糙,大概还有不少bug吧,只是我暂时还没看到。能接受这样的输入:
var globalVar : int = 0;

// a line of comment

function globalFunction() {
    function nestedFunction() {
        /* make a local variable */
        var localVar = ( globalVar = 1 );
    }
    nestedFunction(); // call the nested function
}

globalFunction(); // call the global function


生成这样的语法树:


慢慢再拿这东西继续实验吧。我觉得这个语法文件的命就是要被弄得很乱,呵呵。

话说我对C-like的语言彻底改观了。以前没有自己从头写过语法没有体会,这纯C的语法也是一点都不简单啊。像是for循环的初始化和更新的部分,里面到底应该怎么写才对我现在都还不清楚;下面的语法文件里对forStatement写的很明显是猜的+凑的。Java Language Specification 3rdD 2.0里的定义就很不一样,但这中间的差异可能一直会影响到表达式和语句最基本的规则的写法。到底怎么样比较好,我还是自己慢慢实验慢慢体会吧~

Dolphin.g (2008-03-26 rev 3):
grammar Dolphin;

// Parser

program	:	sourceElements EOF
	;

sourceElements
	:	( sourceElement )+
	;

sourceElement
	:	statement
	|	functionDeclaration
	;

functionDeclaration
	:	FUNCTION Identifier LPAREN formalParameters RPAREN block
	;

formalParameters
	:	formalParameterList
	|	/* empty */
	;

formalParameterList
	:	parameter ( COMMA parameter)*
	;

parameter
	:	Identifier ( COLON TypeSpecifier )?
	;

block
	:	LBRACE sourceElements RBRACE
	;

statement
	:	block
	|	variableStatement
	|	expressionStatement
	|	selectionStatement
	|	iterationStatement
	|	breakStatement
	|	continueStatement
	|	returnStatement
	|	emptyStatement
	;

variableStatement
	:	VAR variableDeclarationList SEMICOLON
	;

variableDeclarationList
	:	variableDeclaration ( COMMA variableDeclaration )*
	;

variableDeclaration
	:	Identifier ( COLON TypeSpecifier )? ( initialiser )?
	;

initialiser
	:	AssignmentOperator expression
	;

selectionStatement
	:	ifStatement
//	|	switchStatement
	;

ifStatement
	:	IF LPAREN expression RPAREN statement
	;

//switchStatement
//	:	
//	;

iterationStatement
	:	doWhileStatement
	|	whileStatement
	|	forStatement
	;

doWhileStatement
	:	DO statement WHILE LPAREN expression RPAREN SEMICOLON
	;

whileStatement
	:	WHILE LPAREN expression RPAREN statement
	;

forStatement
	:	FOR LPAREN ( VAR variableDeclaration | statementExpressionList )? SEMICOLON expression? SEMICOLON statementExpressionList? RPAREN statement
	;

breakStatement
	:	BREAK SEMICOLON
	;

continueStatement
	:	CONTINUE SEMICOLON
	;

returnStatement
	:	RETURN expression? SEMICOLON
	;

emptyStatement
	:	/* empty */ SEMICOLON
	;

expressionStatement
	:	expression SEMICOLON
	;

statementExpressionList
	:	statementExpression ( COMMA statementExpression )*
	;

statementExpression
	:	expression // TODO: this rule requires further refactoring
	;

expression
	:	assignmentExpression
	|	simpleExpression
	;

assignmentExpression
	:	Identifier ( AssignmentOperator | AssignmentShorthandOperator ) expression
	;

simpleExpression
	:	additiveExpression ( RelationalOperator additiveExpression )?
	;

additiveExpression
	:	multiplicativeExpression ( AddOperator multiplicativeExpression )*
	;

multiplicativeExpression
	:	primaryExpression ( MulOperator primaryExpression )*
	;

primaryExpression
	:	LPAREN expression RPAREN
	|	functionInvocationExpression
	|	Identifier // variable
	|	literal
	;

functionInvocationExpression
	:	Identifier LPAREN argumentList RPAREN
	;

argumentList
	:	expression ( COMMA expression )*
	|	/* empty */
	;

literal	:	integerLiteral
	|	FloatingPointLiteral
	|	CharacterLiteral
	|	StringLiteral
	|	BooleanLiteral
	|	NullLiteral
	;

integerLiteral
	:	HexLiteral
	|	OctalLiteral
	|	DecimalLiteral
	;

// Lexer

AssignmentShorthandOperator
	:	( '+=' | '-=' | '*=' | '/=' | '%=' )
	;

RelationalOperator
	:	( '<' | '>' | '==' | '<=' | '>=' | '!=' )
	;

AddOperator
	:	( '+' | '-' )
	;

MulOperator
	:	( '*' | '/' | '%' )
	;

AssignmentOperator
	:	'='
	;

COMMA	:	','
	;

COLON	:	':'
	;

SEMICOLON
	:	';'
	;

LPAREN	:	'('
	;

RPAREN	:	')'
	;

LBRACE	:	'{'
	;

RBRACE	:	'}'
	;

BREAK	:	'break'
	;

CONTINUE:	'continue'
	;

DO	:	'do'
	;

FOR	:	'for'
	;

FUNCTION:	'function'
	;

IF	:	'if'
	;

RETURN	:	'return'
	;

VAR	:	'var'
	;

WHILE	:	'while'
	;

HexLiteral
	:	'0' ('x'|'X') HexDigit+ IntegerTypeSuffix?
	;

DecimalLiteral
	:	('0' | '1'..'9' '0'..'9'*) IntegerTypeSuffix?
	;

OctalLiteral
	:	'0' ('0'..'7')+ IntegerTypeSuffix?
	;

fragment
HexDigit:	('0'..'9'|'a'..'f'|'A'..'F')
	;

fragment
IntegerTypeSuffix
	:	('l'|'L')
	;

FloatingPointLiteral
	:	('0'..'9')+ '.' ('0'..'9')* Exponent? FloatTypeSuffix?
	|	'.' ('0'..'9')+ Exponent? FloatTypeSuffix?
	|	('0'..'9')+ Exponent FloatTypeSuffix?
	;

fragment
Exponent:	('e'|'E') ('+'|'-')? ('0'..'9')+
	;

fragment
FloatTypeSuffix
	:	( 'f' | 'F' | 'd' | 'D' )
	;

BooleanLiteral
	:	'true'
	|	'false'
	;

NullLiteral
	:	'null'
	;

CharacterLiteral
	:	'\'' ( EscapeSequence | ~( '\'' | '\\' ) ) '\''
	;

StringLiteral
	:	'"' ( EscapeSequence | ~( '\\' | '"' ) )* '"'
	;

fragment
EscapeSequence
	:	'\\' ( 'b' | 't' | 'n' | 'f' | 'r' | '\"' | '\'' | '\\' )
	|	UnicodeEscape
	|	OctalEscape
	;

fragment
OctalEscape
	:	'\\' ( '0'..'3' ) ( '0'..'7' ) ( '0'..'7' )
	|	'\\' ( '0'..'7' ) ( '0'..'7' )
	|	'\\' ( '0'..'7' )
	;

fragment
UnicodeEscape
	:	'\\' 'u' HexDigit HexDigit HexDigit HexDigit
	;

TypeSpecifier
	:	'boolean'
	|	'char'
	|	'short'
	|	'int'
	|	'long'
	|	'double'
	|	'string'
	;

Identifier
	:	( 'a'..'z' | 'A'..'Z' ) ( 'a'..'z' | 'A'..'Z' | '0'..'9' )*
	;

WS	:	( ' ' | '\t' | '\r' | '\n' )+ { $channel = HIDDEN; }
	;

Comment
	:	'/*' ( options { greedy = false; } : . )* '*/' { $channel = HIDDEN; }
	;

LineComment
	:	'//' ~('\n'|'\r')* '\r'? '\n' { $channel = HIDDEN; }
	;
分享到:
评论
3 楼 lwwin 2008-03-28  
偶不习惯OO那种繁琐的东西,偶大概能够看懂的也只有C了罢- -!
2 楼 RednaxelaFX 2008-03-28  
lwwin 写道
貌似是比较新的C实现?

没啦。基本上是想从简单的东西做起来找感觉。
这东西从C与ECMAScript 4糅合简化而来的。暂时定义了一些primitive type,以ECMAScript 4/ActionScript 3的形式给变量标注类型(可选标注),然后允许嵌套的函数定义这样。没有面向对象的支持。要把canconial name的问题都考虑上的话好麻烦 T T
总之这个慢慢来……
1 楼 lwwin 2008-03-28  
貌似是比较新的C实现?
支持随机定义貌似-v-+ 好长好长

最近电源坏了- -

相关推荐

    编译原理语法制导翻译器 课程设计

    3、1语法制导定义…………………………………… 2 3、2设计思想………………………………………… 3 3、3基本思路………………………………………… 4 四、设计内容……………………………………………… 4 五、设计...

    Velocity模板技术语法详细介绍

    1.变量………………………………………………………………………………1 2.循环………………………………………………………………………………2 3.条件语句……………………………………………………………………...

    编译原理 语法分析 语法树生成

    本主题主要关注的是“语法分析”和“语法树生成”,特别是如何使用经典的工具yacc(Yet Another Compiler-Compiler)和lex来实现C++语言的语法分析器。 首先,我们来了解一下什么是语法分析。语法分析是编译器设计...

    最新网吧数据库管理助手

    (CREATE DATABASE语法)……] 新加功能:ACCESS文件访问加上密码输入功能,新建ACCESS文件,压缩ACCESS文件功能 界面就让他简单好了。。。 数据库管理助手 功能:浏览,添加,编辑ACCESS数据库、MSSQL数据库...

    JS语法字典 JS语法字典 JS语法字典

    JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典JS语法字典

    编译原理语法树的实现

    语法树,也被称为抽象语法树(Abstract Syntax Tree, AST),是编译器或解释器在解析源代码时构建的一种数据结构,它以树的形式表示程序的语法结构。本文将深入探讨编译原理中语法树的实现,以及其在程序分析、翻译...

    C# 语法全解C# 语法全解

    C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解C# 语法全解

    一个语法分析程序(C语言)

    在编程领域,语法分析是编译器或解释器的核心组成部分,它负责将源代码转换成计算机可以理解的形式。本文将详细探讨一个用C语言编写的语法分析程序的相关知识点。 首先,我们要了解语法分析的基本概念。语法分析是...

    java 实现词法分析器以及语法分析器

    在编程领域,编译原理是理解计算机语言处理过程的关键部分,它涉及到词法分析和语法分析两个重要步骤。本文将详细介绍使用Java实现词法分析器和语法分析器的相关知识点。 词法分析,也称为扫描或Tokenization,是...

    日语三级考试重点语法总结

    日语三级考试是针对日语学习者的中等级别考试,主要测试考生对于日语语法、词汇、读解和听力理解的能力。以下是对日语三级考试中的一些重点语法点的详细解释: 1. お+动词连用形+になる / お+动词连用形+くださ...

    PRD语法、自查、排版……产品需求文档应该酱紫!(附大厂模板).doc

    在撰写PRD时,遵循一定的格式、语法和自查方法至关重要,以确保信息准确无误地传递。 一、PRD的形式 1. 原型附带文字:对于移动端产品,通常会结合原型图进行描述,特别是交互逻辑和取值规则。如果文字较多,可以将...

    日语一级词汇,语法,练习

    【日语一级词汇,语法,练习】是针对日本语能力测试N1级别学习者的重要复习资源,涵盖了词汇、文法和大量的练习题。N1级别是日语能力测试的最高等级,要求考生具备高度的日语读写听说能力。以下是对部分题目中涉及的...

    struts2校验器

    struts2校验器,字段,非字段校验器的语法规则……

    大连理工大学——编译技术-第五次上机-题目1-语法分析2

    目的:熟练掌握自下而上的语法分析方法,并能用程序实现。 要求: 1. 使用如下文法: ... …… 3. 要有一定的错误处理功能。即对错误能提示,并且能在一定程度上忽略尽量少的记号来进行接下来的分析

    高级英语语法(薄冰)下.pdf

    高级英语语法是英语学习中一个深入且必要的领域,它帮助学习者能够掌握和运用复杂的英语句式和表达方式。薄冰所著的《高级英语语法》是该领域的经典教材之一,本书内容涵盖了英语语法的多个方面,其中包括语气、形容...

    LL(1)文法自动生成语法分析程序的设计

    "LL(1)文法自动生成语法分析程序的设计" LL(1)文法是形式语言理论中的一种文法,它是一种基于上下文无关文法的扩展,能够描述很多编程语言的语法结构。LL(1)文法自动生成语法分析程序的设计是指根据输入的LL(1)...

    C#5.0语法范例

    本书是一本针对C#5.0的语法进行讲解和介绍的书籍。在章节安排上共分为二十三章。比较全面地介绍了C#5.0语法的各个语法要点。内容上包括程序基础、基本运算符、语句、类型转换、类、多态、命名空间、接口、访问性约束...

    编译原理LL(1)语法分析实验(四学时)

    实验二 LL(1) 语法分析实验 (4 学时) 【实验目的】 1. 了解 LL(1)语法分析是如何根据语法规则逐一分析词法分析所得到的单 词,检查语法错误,即掌握语法分析过程。 2. 掌握 LL(1)语法分析器的设计与调试。 ...

    北邮编译原理实验二:语法分析程序的设计与实现

    在编译原理中,语法分析是编译器设计的关键阶段之一,主要任务是根据语法规则解析源代码,构建抽象语法树(AST),为后续的语义分析和代码生成提供结构化信息。本实验——“北邮编译原理实验二:语法分析程序的设计...

Global site tag (gtag.js) - Google Analytics