mirror of https://github.com/aamine/cbc
1306 lines
29 KiB
Plaintext
1306 lines
29 KiB
Plaintext
// #@@range/options{
|
|
options {
|
|
STATIC = false;
|
|
DEBUG_PARSER = true;
|
|
UNICODE_INPUT = true;
|
|
}
|
|
// #@@}
|
|
|
|
PARSER_BEGIN(Parser)
|
|
package net.loveruby.cflat.parser;
|
|
import net.loveruby.cflat.compiler.*;
|
|
import net.loveruby.cflat.ast.*;
|
|
import net.loveruby.cflat.type.*;
|
|
import net.loveruby.cflat.asm.*;
|
|
import net.loveruby.cflat.exception.*;
|
|
import java.lang.reflect.*;
|
|
import java.util.*;
|
|
import java.io.*;
|
|
|
|
public class Parser {
|
|
static public AST parseFile(File file, LibraryLoader loader,
|
|
ErrorHandler errorHandler)
|
|
throws SyntaxException, FileException {
|
|
return parseFile(file, loader, errorHandler, false);
|
|
}
|
|
|
|
// #@@range/parseFile{
|
|
static public AST parseFile(File file, LibraryLoader loader,
|
|
ErrorHandler errorHandler, boolean debug)
|
|
throws SyntaxException, FileException {
|
|
return newFileParser(file, loader, errorHandler, debug).parse();
|
|
}
|
|
// #@@}
|
|
|
|
static public Declarations parseDeclFile(File file,
|
|
LibraryLoader loader,
|
|
ErrorHandler errorHandler)
|
|
throws SyntaxException,
|
|
FileException {
|
|
return parseDeclFile(file, loader, errorHandler, false);
|
|
}
|
|
|
|
static public Declarations parseDeclFile(File file,
|
|
LibraryLoader loader,
|
|
ErrorHandler errorHandler,
|
|
boolean debug)
|
|
throws SyntaxException,
|
|
FileException {
|
|
return newFileParser(file, loader, errorHandler, debug).parseDecls();
|
|
}
|
|
|
|
// #@@range/newFileParser{
|
|
static final protected String sourceEncoding = "UTF-8";
|
|
|
|
static public Parser newFileParser(File file,
|
|
LibraryLoader loader,
|
|
ErrorHandler errorHandler,
|
|
boolean debug)
|
|
throws FileException {
|
|
try {
|
|
BufferedReader r =
|
|
new BufferedReader(
|
|
new InputStreamReader(new FileInputStream(file),
|
|
sourceEncoding));
|
|
return new Parser(r, file.getPath(), loader, errorHandler, debug);
|
|
}
|
|
catch (FileNotFoundException ex) {
|
|
throw new FileException(ex.getMessage());
|
|
}
|
|
catch (UnsupportedEncodingException ex) {
|
|
throw new Error("must not happen: " + ex.getMessage());
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/instance_members{
|
|
protected String sourceName;
|
|
protected LibraryLoader loader;
|
|
protected ErrorHandler errorHandler;
|
|
protected LabelPool labelPool;
|
|
protected Set knownTypedefs;
|
|
// #@@}
|
|
|
|
// #@@range/ctor1{
|
|
public Parser(Reader s, String name,
|
|
LibraryLoader loader, ErrorHandler errorHandler) {
|
|
this(s, name, loader, errorHandler, false);
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/ctor2{
|
|
public Parser(Reader s, String name, LibraryLoader loader,
|
|
ErrorHandler errorHandler, boolean debug) {
|
|
this(s);
|
|
this.sourceName = name;
|
|
this.loader = loader;
|
|
this.errorHandler = errorHandler;
|
|
this.labelPool = new LabelPool();
|
|
this.knownTypedefs = new HashSet();
|
|
if (debug) {
|
|
enable_tracing();
|
|
}
|
|
else {
|
|
disable_tracing();
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/parse{
|
|
public AST parse() throws SyntaxException {
|
|
try {
|
|
return compilation_unit();
|
|
}
|
|
catch (TokenMgrError err) {
|
|
throw new SyntaxException(err.getMessage());
|
|
}
|
|
catch (ParseException ex) {
|
|
throw new SyntaxException(ex.getMessage());
|
|
}
|
|
catch (LookaheadSuccess err) {
|
|
throw new SyntaxException("syntax error");
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
public Declarations parseDecls() throws SyntaxException {
|
|
try {
|
|
return declaration_file();
|
|
}
|
|
catch (TokenMgrError ex) {
|
|
throw new SyntaxException(ex.getMessage());
|
|
}
|
|
catch (ParseException ex) {
|
|
throw new SyntaxException(ex.getMessage());
|
|
}
|
|
}
|
|
|
|
private void addKnownTypedefs(Iterator typedefs) {
|
|
while (typedefs.hasNext()) {
|
|
TypedefNode n = (TypedefNode)typedefs.next();
|
|
addType(n.name());
|
|
}
|
|
}
|
|
|
|
private void addType(String name) {
|
|
knownTypedefs.add(name);
|
|
}
|
|
|
|
private boolean isType(String name) {
|
|
return knownTypedefs.contains(name);
|
|
}
|
|
|
|
// #@@range/newReader{
|
|
private IntegerLiteralNode integerNode(Location loc, String image) {
|
|
long i = integerValue(image);
|
|
if (image.endsWith("UL")) {
|
|
return new IntegerLiteralNode(loc, IntegerTypeRef.ulongRef(), i);
|
|
}
|
|
else if (image.endsWith("L")) {
|
|
return new IntegerLiteralNode(loc, IntegerTypeRef.longRef(), i);
|
|
}
|
|
else if (image.endsWith("U")) {
|
|
return new IntegerLiteralNode(loc, IntegerTypeRef.uintRef(), i);
|
|
}
|
|
else {
|
|
return new IntegerLiteralNode(loc, IntegerTypeRef.intRef(), i);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/integerValue{
|
|
private long integerValue(String image) {
|
|
String s = image.replaceFirst("[UL]+", "");
|
|
if (s.startsWith("0x") || s.startsWith("0X")) {
|
|
return Long.parseLong(s.substring(2), 16);
|
|
}
|
|
else if (s.startsWith("0") && !s.equals("0")) {
|
|
return Long.parseLong(s.substring(1), 8);
|
|
}
|
|
else {
|
|
return Long.parseLong(s, 10);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/characterCode{
|
|
private long characterCode(String image) throws ParseException {
|
|
String s = stringValue(image);
|
|
if (s.length() != 1) {
|
|
throw new Error("must not happen: character length > 1");
|
|
}
|
|
return (long)s.charAt(0);
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/stringValue{
|
|
private String stringValue(String _image) throws ParseException {
|
|
int pos = 0;
|
|
int idx;
|
|
StringBuffer buf = new StringBuffer();
|
|
String image = _image.substring(1, _image.length() - 1);
|
|
|
|
while ((idx = image.indexOf("\\", pos)) >= 0) {
|
|
buf.append(image.substring(pos, idx));
|
|
if (image.length() >= idx + 4
|
|
&& Character.isDigit(image.charAt(idx+1))
|
|
&& Character.isDigit(image.charAt(idx+2))
|
|
&& Character.isDigit(image.charAt(idx+3))) {
|
|
buf.append(unescapeOctal(image.substring(idx+1, idx+4)));
|
|
pos = idx + 4;
|
|
}
|
|
else {
|
|
buf.append(unescapeSeq(image.charAt(idx+1)));
|
|
pos = idx + 2;
|
|
}
|
|
}
|
|
if (pos < image.length()) {
|
|
buf.append(image.substring(pos, image.length()));
|
|
}
|
|
return buf.toString();
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/unescapeOctal{
|
|
private static final int charMax = 255;
|
|
|
|
private char unescapeOctal(String digits) throws ParseException {
|
|
int i = Integer.parseInt(digits, 8);
|
|
if (i > charMax) {
|
|
throw new ParseException(
|
|
"octal character sequence too big: \\" + digits);
|
|
}
|
|
return (char)i;
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/unescapeSeq{
|
|
private static final char bell = 7;
|
|
private static final char backspace = 8;
|
|
private static final char escape = 27;
|
|
private static final char vt = 11;
|
|
|
|
private char unescapeSeq(char c) throws ParseException {
|
|
switch (c) {
|
|
case '0': return '\0';
|
|
case '"': return '"';
|
|
case '\'': return '\'';
|
|
case 'a': return bell;
|
|
case 'b': return backspace;
|
|
case 'e': return escape;
|
|
case 'f': return '\f';
|
|
case 'n': return '\n';
|
|
case 'r': return '\r';
|
|
case 't': return '\t';
|
|
case 'v': return vt;
|
|
default:
|
|
throw new ParseException("unknown escape sequence: \"\\" + c);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/location{
|
|
protected Location location(Token t) {
|
|
return new Location(sourceName, t.beginLine, t.beginColumn);
|
|
}
|
|
// #@@}
|
|
}
|
|
PARSER_END(Parser)
|
|
|
|
/*
|
|
* Lexical Rules
|
|
*/
|
|
|
|
// linear-white-spaces
|
|
// #@@range/lex_spaces{
|
|
SPECIAL_TOKEN: { <SPACES: ([" ", "\t", "\n", "\r", "\f"])+> }
|
|
// #@@}
|
|
|
|
// block comment
|
|
// #@@range/lex_block_comment{
|
|
MORE: { <"/*"> : IN_BLOCK_COMMENT }
|
|
<IN_BLOCK_COMMENT> MORE: { <~[]> }
|
|
<IN_BLOCK_COMMENT> SPECIAL_TOKEN: { <BLOCK_COMMENT: "*/"> : DEFAULT }
|
|
// #@@}
|
|
|
|
// line comment
|
|
// #@@range/lex_line_comment{
|
|
SPECIAL_TOKEN: {
|
|
<LINE_COMMENT: "//" (~["\n", "\r"])* ("\n" | "\r\n" | "\r")?>
|
|
}
|
|
// #@@}
|
|
|
|
// reserved words
|
|
// #@@range/lex_reswords{
|
|
TOKEN: {
|
|
<VOID : "void">
|
|
| <CHAR : "char">
|
|
| <SHORT : "short">
|
|
| <INT : "int">
|
|
| <LONG : "long">
|
|
| <STRUCT : "struct">
|
|
| <UNION : "union">
|
|
| <ENUM : "enum">
|
|
| <STATIC : "static">
|
|
| <EXTERN : "extern">
|
|
| <SIGNED : "signed">
|
|
| <UNSIGNED : "unsigned">
|
|
| <IF : "if">
|
|
| <ELSE : "else">
|
|
| <SWITCH : "switch">
|
|
| <CASE : "case">
|
|
| <DEFAULT_ : "default">
|
|
| <WHILE : "while">
|
|
| <DO : "do">
|
|
| <FOR : "for">
|
|
| <RETURN : "return">
|
|
| <BREAK : "break">
|
|
| <CONTINUE : "continue">
|
|
| <GOTO : "goto">
|
|
| <TYPEDEF : "typedef">
|
|
| <IMPORT : "import">
|
|
}
|
|
// #@@}
|
|
|
|
// identifier
|
|
// #@@range/lex_ident{
|
|
TOKEN: {
|
|
<IDENTIFIER: ["a"-"z", "A"-"Z", "_"] (["a"-"z", "A"-"Z", "_", "0"-"9"])*>
|
|
}
|
|
// #@@}
|
|
|
|
// integer literals
|
|
// #@@range/lex_integer{
|
|
TOKEN: {
|
|
<INTEGER: ["1"-"9"] (["0"-"9"])* ("U")? ("L")?
|
|
| "0" ["x", "X"] (["0"-"9", "a"-"f", "A"-"F"])+ ("U")? ("L")?
|
|
| "0" (["0"-"7"])* ("U")? ("L")?
|
|
>
|
|
}
|
|
// #@@}
|
|
|
|
// character literal
|
|
// #@@range/lex_char{
|
|
MORE: { <"'"> : IN_CHARACTER } // rule1
|
|
<IN_CHARACTER> MORE: {
|
|
<~["'", "\\", "\n", "\r"]> : CHARACTER_TERM // rule2
|
|
| <"\\" (["0"-"7"]){3}> : CHARACTER_TERM // rule3
|
|
| <"\\" ~[]> : CHARACTER_TERM // rule4
|
|
}
|
|
<CHARACTER_TERM> TOKEN: { <CHARACTER: "'"> : DEFAULT } // rule5
|
|
// #@@}
|
|
|
|
// string literal
|
|
// #@@range/lex_string{
|
|
MORE: { <"\""> : IN_STRING }
|
|
<IN_STRING> MORE: {
|
|
<(~["\"", "\\", "\n", "\r"])+>
|
|
| <"\\" (["0"-"7"]){3}>
|
|
| <"\\" ~[]>
|
|
}
|
|
<IN_STRING> TOKEN: { <STRING: "\""> : DEFAULT }
|
|
// #@@}
|
|
|
|
/*
|
|
* Grammar
|
|
*/
|
|
|
|
// #@@range/compilation_unit{
|
|
AST compilation_unit():
|
|
{
|
|
Token t;
|
|
Declarations impdecls, decls;
|
|
}
|
|
{
|
|
{
|
|
t = getToken(1);
|
|
}
|
|
impdecls=import_stmts() decls=top_defs() <EOF>
|
|
{
|
|
decls.add(impdecls);
|
|
return new AST(sourceName, decls, t);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/declaration_file{
|
|
Declarations declaration_file():
|
|
{
|
|
Declarations impdecls, decls = new Declarations();
|
|
UndefinedFunction funcdecl;
|
|
UndefinedVariable vardecl;
|
|
StructNode defstruct;
|
|
UnionNode defunion;
|
|
TypedefNode typedef;
|
|
}
|
|
{
|
|
impdecls=import_stmts()
|
|
{
|
|
decls.add(impdecls);
|
|
}
|
|
( LOOKAHEAD(<EXTERN> typeref() <IDENTIFIER> "(")
|
|
funcdecl=funcdecl() { decls.addFuncdecl(funcdecl); }
|
|
| vardecl=vardecl() { decls.addVardecl(vardecl); }
|
|
| defstruct=defstruct() { decls.addDefstruct(defstruct); }
|
|
| defunion=defunion() { decls.addDefunion(defunion); }
|
|
| typedef=typedef() { decls.addTypedef(typedef); }
|
|
)*
|
|
<EOF>
|
|
{
|
|
return decls;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/import_stmts{
|
|
Declarations import_stmts():
|
|
{
|
|
String libid;
|
|
Declarations impdecls = new Declarations();
|
|
}
|
|
{
|
|
(libid=import_stmt()
|
|
{
|
|
try {
|
|
Declarations decls = loader.loadLibrary(libid, errorHandler);
|
|
if (decls != null) {
|
|
impdecls.add(decls);
|
|
addKnownTypedefs(decls.typedefs().iterator());
|
|
}
|
|
}
|
|
catch (CompileException ex) {
|
|
throw new ParseException(ex.getMessage());
|
|
}
|
|
}
|
|
)*
|
|
{
|
|
return impdecls;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/import_stmt{
|
|
String import_stmt():
|
|
{
|
|
StringBuffer buf = new StringBuffer();
|
|
String n;
|
|
}
|
|
{
|
|
<IMPORT> n=name() { buf.append(n); }
|
|
("." n=name() { buf.append("."); buf.append(n); } )*
|
|
";"
|
|
{
|
|
return buf.toString();
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/top_defs{
|
|
Declarations top_defs():
|
|
{
|
|
Declarations decls = new Declarations();
|
|
DefinedFunction defun;
|
|
List defvars;
|
|
StructNode defstruct;
|
|
UnionNode defunion;
|
|
TypedefNode typedef;
|
|
}
|
|
{
|
|
( LOOKAHEAD(storage() typeref() <IDENTIFIER> "(")
|
|
defun=defun() { decls.addDefun(defun); }
|
|
| LOOKAHEAD(3)
|
|
defvars=defvars() { decls.addDefvars(defvars); }
|
|
| defstruct=defstruct() { decls.addDefstruct(defstruct); }
|
|
| defunion=defunion() { decls.addDefunion(defunion); }
|
|
| typedef=typedef() { decls.addTypedef(typedef); }
|
|
)*
|
|
{
|
|
return decls;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/defvars{
|
|
List defvars():
|
|
{
|
|
List defs = new ArrayList();
|
|
boolean priv;
|
|
TypeNode type;
|
|
String name;
|
|
ExprNode init = null;
|
|
}
|
|
{
|
|
priv=storage() type=type() name=name() ["=" init=expr()]
|
|
{
|
|
defs.add(new DefinedVariable(priv, type, name, init));
|
|
init = null;
|
|
}
|
|
( "," name=name() ["=" init=expr()]
|
|
{
|
|
defs.add(new DefinedVariable(priv, type, name, init));
|
|
init = null;
|
|
}
|
|
)* ";"
|
|
{
|
|
return defs;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/defun{
|
|
DefinedFunction defun():
|
|
{
|
|
boolean priv;
|
|
TypeRef ref;
|
|
String n;
|
|
Params ps;
|
|
BlockNode body;
|
|
}
|
|
{
|
|
priv=storage() ref=typeref() n=name() "(" ps=params() ")" body=block()
|
|
{
|
|
Params ptypes = ps.typeRefs();
|
|
TypeNode t = new TypeNode(new PointerTypeRef(
|
|
new FunctionTypeRef(ref, ptypes)));
|
|
return new DefinedFunction(labelPool, priv, t, n, ps, body);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/storage{
|
|
boolean storage():
|
|
{ Token t = null; }
|
|
{
|
|
[t=<STATIC>] { return (t == null ? false : true); }
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/storage{
|
|
Params params():
|
|
{
|
|
Token t;
|
|
FixedParams params;
|
|
}
|
|
{
|
|
LOOKAHEAD(<VOID> ")")
|
|
t=<VOID>
|
|
{
|
|
return new FixedParams(location(t), new ArrayList());
|
|
}
|
|
| params=fixedparams()
|
|
["," "..." { return new VarParams(params); }]
|
|
{
|
|
return params;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/fixedparams{
|
|
FixedParams fixedparams():
|
|
{
|
|
List params = new ArrayList();
|
|
Parameter param, param1;
|
|
}
|
|
{
|
|
param1=param() { params.add(param1); }
|
|
( LOOKAHEAD(2) "," param=param() { params.add(param); } )*
|
|
{
|
|
return new FixedParams(param1.location(), params);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/param{
|
|
Parameter param():
|
|
{
|
|
TypeNode t;
|
|
String n;
|
|
}
|
|
{
|
|
t=type() n=name() { return new Parameter(t, n); }
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/block{
|
|
BlockNode block():
|
|
{
|
|
Token t;
|
|
List vars;
|
|
List stmts;
|
|
}
|
|
{
|
|
t="{" vars=defvar_list() stmts=stmts() "}"
|
|
{
|
|
return new BlockNode(location(t), vars, stmts);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
|
|
// #@@range/defvar_list{
|
|
List defvar_list():
|
|
{
|
|
List result = new ArrayList();
|
|
List vars;
|
|
}
|
|
{
|
|
( vars=defvars() { result.addAll(vars); } )*
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/defstruct{
|
|
StructNode defstruct():
|
|
{
|
|
Token t;
|
|
String n;
|
|
List membs;
|
|
}
|
|
{
|
|
t=<STRUCT> n=name() membs=member_list() ";"
|
|
{
|
|
return new StructNode(location(t), new StructTypeRef(n), n, membs);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
UnionNode defunion():
|
|
{
|
|
Token t;
|
|
String n;
|
|
List membs;
|
|
}
|
|
{
|
|
t=<UNION> n=name() membs=member_list() ";"
|
|
{
|
|
return new UnionNode(location(t), new UnionTypeRef(n), n, membs);
|
|
}
|
|
}
|
|
|
|
// #@@range/member_list{
|
|
List member_list():
|
|
{
|
|
List membs = new ArrayList();
|
|
Slot s;
|
|
}
|
|
{
|
|
"{" (s=slot() ";" { membs.add(s); })* "}"
|
|
{
|
|
return membs;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/slot{
|
|
Slot slot():
|
|
{
|
|
TypeNode t;
|
|
String n;
|
|
}
|
|
{
|
|
t=type() n=name() { return new Slot(t, n); }
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/funcdecl{
|
|
UndefinedFunction funcdecl():
|
|
{
|
|
TypeRef ref;
|
|
String n;
|
|
Params ps;
|
|
}
|
|
{
|
|
<EXTERN> ref=typeref() n=name() "(" ps=params() ")" ";"
|
|
{
|
|
Params ptyperefs = ps.typeRefs();
|
|
TypeNode t = new TypeNode(new PointerTypeRef(
|
|
new FunctionTypeRef(ref, ptyperefs)));
|
|
return new UndefinedFunction(t, n, ps);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
UndefinedVariable vardecl():
|
|
{
|
|
TypeNode t;
|
|
String n;
|
|
}
|
|
{
|
|
<EXTERN> t=type() n=name() ";"
|
|
{
|
|
return new UndefinedVariable(t, n);
|
|
}
|
|
}
|
|
|
|
// #@@range/type{
|
|
TypeNode type():
|
|
{ TypeRef ref; }
|
|
{
|
|
ref=typeref() { return new TypeNode(ref); }
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/typeref{
|
|
TypeRef typeref():
|
|
{
|
|
TypeRef ref;
|
|
Token t;
|
|
Params params;
|
|
}
|
|
{
|
|
ref=typeref_base()
|
|
( LOOKAHEAD(2)
|
|
"[" "]"
|
|
{
|
|
ref = new ArrayTypeRef(ref);
|
|
}
|
|
| "[" t=<INTEGER> "]"
|
|
{
|
|
ref = new ArrayTypeRef(ref, integerValue(t.image));
|
|
}
|
|
| "*"
|
|
{
|
|
ref = new PointerTypeRef(ref);
|
|
}
|
|
| "(" "*" ")" "(" params=param_typerefs() ")"
|
|
{
|
|
ref = new PointerTypeRef(new FunctionTypeRef(ref, params));
|
|
}
|
|
)*
|
|
{
|
|
return ref;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/param_typerefs{
|
|
Params param_typerefs():
|
|
{ FixedParams params; }
|
|
{
|
|
LOOKAHEAD(<VOID> ")")
|
|
<VOID>
|
|
{
|
|
return new FixedParams(new ArrayList());
|
|
}
|
|
| params=fixedparam_typerefs()
|
|
[ "," "..." { return new VarParams(params); } ]
|
|
{
|
|
return params;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/fixedparam_typerefs{
|
|
FixedParams fixedparam_typerefs():
|
|
{
|
|
List refs = new ArrayList();
|
|
TypeRef ref;
|
|
}
|
|
{
|
|
ref=typeref() { refs.add(ref); }
|
|
( LOOKAHEAD(2) "," ref=typeref() { refs.add(ref); } )*
|
|
{
|
|
return new FixedParams(refs);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/typeref_base{
|
|
TypeRef typeref_base():
|
|
{
|
|
Token t, name;
|
|
}
|
|
{
|
|
t=<VOID> { return new VoidTypeRef(location(t)); }
|
|
| t=<CHAR> { return IntegerTypeRef.charRef(location(t)); }
|
|
| t=<SHORT> { return IntegerTypeRef.shortRef(location(t)); }
|
|
| t=<INT> { return IntegerTypeRef.intRef(location(t)); }
|
|
| t=<LONG> { return IntegerTypeRef.longRef(location(t)); }
|
|
| LOOKAHEAD(2) t=<UNSIGNED> <CHAR>
|
|
{ return IntegerTypeRef.ucharRef(location(t)); }
|
|
| LOOKAHEAD(2) t=<UNSIGNED> <SHORT>
|
|
{ return IntegerTypeRef.ushortRef(location(t)); }
|
|
| LOOKAHEAD(2) t=<UNSIGNED> <INT>
|
|
{ return IntegerTypeRef.uintRef(location(t)); }
|
|
| t=<UNSIGNED> <LONG>
|
|
{ return IntegerTypeRef.ulongRef(location(t)); }
|
|
| t=<STRUCT> name=<IDENTIFIER>
|
|
{ return new StructTypeRef(location(t), name.image); }
|
|
| t=<UNION> name=<IDENTIFIER>
|
|
{ return new UnionTypeRef(location(t), name.image); }
|
|
| LOOKAHEAD({isType(getToken(1).image)}) name=<IDENTIFIER>
|
|
{ return new UserTypeRef(location(name), name.image); }
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/typedef{
|
|
TypedefNode typedef():
|
|
{
|
|
Token t;
|
|
TypeRef ref;
|
|
Token newname;
|
|
}
|
|
{
|
|
t=<TYPEDEF> ref=typeref() newname=<IDENTIFIER> ";"
|
|
{
|
|
addType(newname.image);
|
|
return new TypedefNode(location(t), ref, newname.image);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/stmts{
|
|
List stmts():
|
|
{
|
|
List ss = new ArrayList();
|
|
Node s;
|
|
}
|
|
{
|
|
(s=stmt() { if (s != null) ss.add(s); })*
|
|
{
|
|
return ss;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/stmt{
|
|
Node stmt():
|
|
{ Node n = null; }
|
|
{
|
|
( ";"
|
|
| LOOKAHEAD(2) n=labeled_stmt()
|
|
| n=expr() ";"
|
|
| n=block()
|
|
| n=if_stmt()
|
|
| n=while_stmt()
|
|
| n=dowhile_stmt()
|
|
| n=for_stmt()
|
|
| n=switch_stmt()
|
|
| n=break_stmt()
|
|
| n=continue_stmt()
|
|
| n=goto_stmt()
|
|
| n=return_stmt()
|
|
)
|
|
{
|
|
return n;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
LabelNode labeled_stmt():
|
|
{
|
|
Token t;
|
|
Node n;
|
|
}
|
|
{
|
|
t=<IDENTIFIER> ":" n=stmt()
|
|
{
|
|
return new LabelNode(location(t), t.image, n);
|
|
}
|
|
}
|
|
|
|
// #@@range/if_stmt{
|
|
IfNode if_stmt():
|
|
{
|
|
Token t;
|
|
ExprNode cond;
|
|
Node thenBody, elseBody = null;
|
|
}
|
|
{
|
|
t=<IF> "(" cond=expr() ")" thenBody=stmt()
|
|
[LOOKAHEAD(1) <ELSE> elseBody=stmt()]
|
|
{
|
|
return new IfNode(location(t), labelPool, cond, thenBody, elseBody);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/while_stmt{
|
|
WhileNode while_stmt():
|
|
{
|
|
Token t;
|
|
ExprNode cond;
|
|
Node body;
|
|
}
|
|
{
|
|
t=<WHILE> "(" cond=expr() ")" body=stmt()
|
|
{
|
|
return new WhileNode(location(t), labelPool, cond, body);
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
DoWhileNode dowhile_stmt():
|
|
{
|
|
Token t;
|
|
ExprNode cond;
|
|
Node body;
|
|
}
|
|
{
|
|
t=<DO> body=stmt() <WHILE> "(" cond=expr() ")" ";"
|
|
{
|
|
return new DoWhileNode(location(t), labelPool, body, cond);
|
|
}
|
|
}
|
|
|
|
ForNode for_stmt():
|
|
{
|
|
Token t;
|
|
ExprNode init = null, cond = null, incr = null;
|
|
Node body;
|
|
}
|
|
{
|
|
t=<FOR> "(" [init=expr()] ";"
|
|
[cond=expr()] ";"
|
|
[incr=expr()] ")" body=stmt()
|
|
{
|
|
return new ForNode(location(t), labelPool, init, cond, incr, body);
|
|
}
|
|
}
|
|
|
|
SwitchNode switch_stmt():
|
|
{
|
|
Token t;
|
|
ExprNode cond;
|
|
List bodies;
|
|
}
|
|
{
|
|
t=<SWITCH> "(" cond=expr() ")" "{" bodies=case_clauses() "}"
|
|
{
|
|
return new SwitchNode(location(t), labelPool, cond, bodies);
|
|
}
|
|
}
|
|
|
|
List case_clauses():
|
|
{
|
|
List clauses = new ArrayList();
|
|
Node n;
|
|
}
|
|
{
|
|
(n=case_clause() { clauses.add(n); })*
|
|
[n=default_clause() { clauses.add(n); }]
|
|
{
|
|
return clauses;
|
|
}
|
|
}
|
|
|
|
CaseNode case_clause():
|
|
{
|
|
List values;
|
|
BlockNode body;
|
|
}
|
|
{
|
|
values=cases() body=case_body()
|
|
{
|
|
return new CaseNode(labelPool, values, body);
|
|
}
|
|
}
|
|
|
|
List cases():
|
|
{
|
|
List values = new ArrayList();
|
|
ExprNode n;
|
|
}
|
|
{
|
|
(<CASE> n=primary() ":" { values.add(n); })+
|
|
{
|
|
return values;
|
|
}
|
|
}
|
|
|
|
CaseNode default_clause():
|
|
{ BlockNode body; }
|
|
{
|
|
<DEFAULT_> ":" body=case_body()
|
|
{
|
|
return new CaseNode(labelPool, new ArrayList(), body);
|
|
}
|
|
}
|
|
|
|
BlockNode case_body():
|
|
{
|
|
LinkedList ss = new LinkedList();
|
|
Node s;
|
|
}
|
|
{
|
|
(s=stmt() { if (s != null) ss.add(s); })+
|
|
{
|
|
// last stmt of case clause must be break stmt.
|
|
if (! (ss.getLast() instanceof BreakNode)) {
|
|
throw new ParseException(
|
|
"missing break statement at the last of case clause");
|
|
}
|
|
return new BlockNode(((Node)ss.get(0)).location(),
|
|
new ArrayList(), ss);
|
|
}
|
|
}
|
|
|
|
GotoNode goto_stmt():
|
|
{ Token t, name; }
|
|
{
|
|
t=<GOTO> name=<IDENTIFIER> ";"
|
|
{
|
|
return new GotoNode(location(t), name.image);
|
|
}
|
|
}
|
|
|
|
// #@@range/break_stmt{
|
|
BreakNode break_stmt():
|
|
{ Token t; }
|
|
{
|
|
t=<BREAK> ";" { return new BreakNode(location(t)); }
|
|
}
|
|
// #@@}
|
|
|
|
ContinueNode continue_stmt():
|
|
{ Token t; }
|
|
{
|
|
t=<CONTINUE> ";" { return new ContinueNode(location(t)); }
|
|
}
|
|
|
|
ReturnNode return_stmt():
|
|
{
|
|
Token t;
|
|
ExprNode expr;
|
|
}
|
|
{
|
|
LOOKAHEAD(2) t=<RETURN> ";" { return new ReturnNode(location(t), null); }
|
|
| t=<RETURN> expr=expr() ";" { return new ReturnNode(location(t), expr); }
|
|
}
|
|
|
|
// #@@range/expr{
|
|
ExprNode expr():
|
|
{
|
|
ExprNode lhs, rhs, expr;
|
|
String op;
|
|
}
|
|
{
|
|
LOOKAHEAD(term() "=")
|
|
lhs=term() "=" rhs=expr()
|
|
{
|
|
return new AssignNode(lhs, rhs);
|
|
}
|
|
| LOOKAHEAD(term() opassign_op())
|
|
lhs=term() op=opassign_op() rhs=expr()
|
|
{
|
|
return new OpAssignNode(lhs, op, rhs);
|
|
}
|
|
| expr=expr10()
|
|
{
|
|
return expr;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/opassign_op{
|
|
String opassign_op(): {}
|
|
{
|
|
( "+=" { return "+"; }
|
|
| "-=" { return "-"; }
|
|
| "*=" { return "*"; }
|
|
| "/=" { return "/"; }
|
|
| "%=" { return "%"; }
|
|
| "&=" { return "&"; }
|
|
| "|=" { return "|"; }
|
|
| "^=" { return "^"; }
|
|
| "<<=" { return "<<"; }
|
|
| ">>=" { return ">>"; }
|
|
)
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr10{
|
|
ExprNode expr10():
|
|
{ ExprNode c, t, e; }
|
|
{
|
|
c=expr9() ["?" t=expr() ":" e=expr10()
|
|
{ return new CondExprNode(labelPool, c, t, e); }]
|
|
{
|
|
return c;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr9{
|
|
ExprNode expr9():
|
|
{ ExprNode l, r; }
|
|
{
|
|
l=expr8() ("||" r=expr8() { l = new LogicalOrNode(labelPool, l, r); })*
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr8{
|
|
ExprNode expr8():
|
|
{ ExprNode l, r; }
|
|
{
|
|
l=expr7() ("&&" r=expr7() { l = new LogicalAndNode(labelPool, l, r); })*
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr7{
|
|
ExprNode expr7():
|
|
{ ExprNode l, r; }
|
|
{
|
|
l=expr6() ( ">" r=expr6() { l = new BinaryOpNode(l, ">", r); }
|
|
| "<" r=expr6() { l = new BinaryOpNode(l, "<", r); }
|
|
| ">=" r=expr6() { l = new BinaryOpNode(l, ">=", r); }
|
|
| "<=" r=expr6() { l = new BinaryOpNode(l, "<=", r); }
|
|
| "==" r=expr6() { l = new BinaryOpNode(l, "==", r); }
|
|
| "!=" r=expr6() { l = new BinaryOpNode(l, "!=", r); } )*
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr6{
|
|
ExprNode expr6():
|
|
{ ExprNode l, r; }
|
|
{
|
|
l=expr5() ("|" r=expr5() { l = new BinaryOpNode(l, "|", r); })*
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr5{
|
|
ExprNode expr5():
|
|
{ ExprNode l, r; }
|
|
{
|
|
l=expr4() ("^" r=expr4() { l = new BinaryOpNode(l, "^", r); })*
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr4{
|
|
ExprNode expr4():
|
|
{ ExprNode l, r; }
|
|
{
|
|
l=expr3() ("&" r=expr3() { l = new BinaryOpNode(l, "&", r); })*
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr3{
|
|
ExprNode expr3():
|
|
{ ExprNode l, r; }
|
|
{
|
|
l=expr2() ( ">>" r=expr2() { l = new BinaryOpNode(l, ">>", r); }
|
|
| "<<" r=expr2() { l = new BinaryOpNode(l, "<<", r); }
|
|
)*
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr2{
|
|
ExprNode expr2():
|
|
{ ExprNode l, r; }
|
|
{
|
|
l=expr1() ( "+" r=expr1() { l = new BinaryOpNode(l, "+", r); }
|
|
| "-" r=expr1() { l = new BinaryOpNode(l, "-", r); }
|
|
)*
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/expr1{
|
|
ExprNode expr1():
|
|
{ ExprNode l, r; }
|
|
{
|
|
l=term() ( "*" r=term() { l = new BinaryOpNode(l, "*", r); }
|
|
| "/" r=term() { l = new BinaryOpNode(l, "/", r); }
|
|
| "%" r=term() { l = new BinaryOpNode(l, "%", r); }
|
|
)*
|
|
{
|
|
return l;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/term{
|
|
ExprNode term():
|
|
{
|
|
TypeNode t;
|
|
ExprNode n;
|
|
}
|
|
{
|
|
LOOKAHEAD("(" type())
|
|
"(" t=type() ")" n=term() { return new CastNode(t, n); }
|
|
| n=unary() { return n; }
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/unary{
|
|
ExprNode unary():
|
|
{
|
|
ExprNode n;
|
|
}
|
|
{
|
|
"++" n=unary() { return new PrefixOpNode("++", n); }
|
|
| "--" n=unary() { return new PrefixOpNode("--", n); }
|
|
| "+" n=term() { return new UnaryOpNode("+", n); }
|
|
| "-" n=term() { return new UnaryOpNode("-", n); }
|
|
| "!" n=term() { return new UnaryOpNode("!", n); }
|
|
| "~" n=term() { return new UnaryOpNode("~", n); }
|
|
| "*" n=term() { return new DereferenceNode(n); }
|
|
| "&" n=term() { return new AddressNode(n); }
|
|
| n=postfix() { return n; }
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/postfix{
|
|
ExprNode postfix():
|
|
{
|
|
ExprNode expr, idx;
|
|
String memb;
|
|
List args;
|
|
}
|
|
{
|
|
expr=primary()
|
|
( "++" { expr = new SuffixOpNode("++", expr); }
|
|
| "--" { expr = new SuffixOpNode("--", expr); }
|
|
| "[" idx=expr() "]" { expr = new ArefNode(expr, idx); }
|
|
| "." memb=name() { expr = new MemberNode(expr, memb); }
|
|
| "->" memb=name() { expr = new PtrMemberNode(expr, memb); }
|
|
| "(" args=args() ")" { expr = new FuncallNode(expr, args); }
|
|
)*
|
|
{
|
|
return expr;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/name{
|
|
String name():
|
|
{ Token t; }
|
|
{
|
|
t=<IDENTIFIER> { return t.image; }
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/args{
|
|
List args():
|
|
{
|
|
List args = new ArrayList();
|
|
ExprNode arg;
|
|
}
|
|
{
|
|
[ arg=expr() { args.add(arg); }
|
|
("," arg=expr() { args.add(arg); })* ]
|
|
{
|
|
return args;
|
|
}
|
|
}
|
|
// #@@}
|
|
|
|
// #@@range/primary{
|
|
ExprNode primary():
|
|
{
|
|
Token t;
|
|
ExprNode n;
|
|
}
|
|
{
|
|
t=<INTEGER>
|
|
{
|
|
return integerNode(location(t), t.image);
|
|
}
|
|
| t=<CHARACTER>
|
|
{
|
|
return new IntegerLiteralNode(location(t),
|
|
IntegerTypeRef.charRef(),
|
|
characterCode(t.image));
|
|
}
|
|
| t=<STRING>
|
|
{
|
|
return new StringLiteralNode(location(t),
|
|
new PointerTypeRef(IntegerTypeRef.charRef()),
|
|
stringValue(t.image));
|
|
}
|
|
| t=<IDENTIFIER>
|
|
{
|
|
return new VariableNode(location(t), t.image);
|
|
}
|
|
| "(" n=expr() ")"
|
|
{
|
|
return n;
|
|
}
|
|
}
|
|
// #@@}
|