using System.Collections.Generic; COMPILER MicroC /* Lexer and parser specification for MicroC. Modified, corrected and simplified from C.ATG "An attempt to describe a subset of C", distributed with Frankie Arzu's CoCo/R for C/C++. sestoft@itu.dk 2008-03-09 Compile with: Coco -namespace MicroC MicroC.ATG csc MicroC.cs Scanner.cs Parser.cs RESTRICTIONS Only one-dimensional arrays. Only void functions; no return statement. No function pointers. No casts. ... more ... */ // The result of the parsing process is a Program public Program program; // A T2V transforms a type to a variable declaration. Used // when parsing the obnoxious C variable declarations in VarDesc public delegate VarDecl T2V(Type t); CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" . digit = "0123456789" . hexdigit = digit + "ABCDEFabcdef" . cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = ( "_" | letter) { "_" | letter | digit } . number = digit {digit}. lpar = '('. COMMENTS FROM "/*" TO "*/" COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS /* ---------------------------------------------------------------------- */ /* Identifiers and numbers */ Ident = ident (. name = t.val; .) . Number = number (. val = Convert.ToInt32(t.val); .) . /* ---------------------------------------------------------------------- */ /* A MicroC program consists of variable and function declarations */ MicroC (. program = new Program(); VarDecl varDecl; .) = { "void" FunctionDef | VarDec ";" (. program.AddVar(varDecl); .) } EOF . /* ---------------------------------------------------------------------- */ /* Base types. The bool type is MicroC only, not C. */ Typ (. ty = Type.errorType; .) = "int" (. ty = Type.intType; .) | "bool" (. ty = Type.boolType; .) . /* Array types. Only one-dimensional arrays. */ ArraySize (. int n; size = null; .) = "[" [ Number (. size = n; .) ] "]" . /* ---------------------------------------------------------------------- */ /* Function definitions */ FunctionDef (. String name; Block body; List parList = new List(); .) = Ident "(" [ FormalParamList ] ")" BlockStmt (. VarDecl[] parameters = parList.ToArray(); program.AddFun(new FunDecl(name, parameters, body)); .) . FormalParamList<.List parList.> (. VarDecl parameter; .) = VarDec (. parList.Add(parameter); .) { "," VarDec (. parList.Add(parameter); .) } . /* ---------------------------------------------------------------------- */ /* Statements */ Stmt (. stmt = null; Block block; VarDecl varDecl; Expression e; .) = ExprStmt | BlockStmt (. stmt = block; .) | IfStmt | NullStmt | WhileStmt | "read" Expr ";" (. stmt = new Read(e.MakeLvalue()); .) | VarDec ";" (. stmt = varDecl; .) . ExprStmt (. Expression e; .) = Expr ";" (. stmt = new ExprStatement(e); .) . BlockStmt (. Statement stmt; List stmtList = new List(); .) = "{" { Stmt (. stmtList.Add(stmt); .) } "}" (. block = new Block(stmtList.ToArray()); .) . IfStmt (. Expression e; Statement s1, s2 = Block.Empty; .) = "if" "(" Expr ")" Stmt [ "else" Stmt ] (. stmt = new IfElse(e, s1, s2); .) . NullStmt = ";" (. stmt = new Block(); .) . WhileStmt (. Expression e; Statement body; .) = "while" "(" Expr ")" Stmt (. stmt = new While(e, body); .) . /* ---------------------------------------------------------------------- */ /* Declaration of local or global variable or formal parameter. A VarDec is a variable declaration. A VarDesc is a variable description, consisting of the pointer/array decorations and the variable name, but not the base type. */ VarDec (. Type ty; T2V t2v; .) = Typ VarDesc (. varDecl = t2v(ty); .) . VarDesc (. String name; int? size; t2v = null; .) = ( Ident (. t2v = delegate(Type ty) { return new VarDecl(name, ty); }; .) | "*" VarDesc (. T2V outer = t2v; t2v = delegate(Type ty) { return outer(new PointerType(ty)); }; .) | "(" VarDesc ")" ) [ ArraySize (. T2V outer = t2v; t2v = delegate(Type ty) { return outer(new ArrayType(ty, size)); }; .) ] . /* ---------------------------------------------------------------------- */ /* Expressions, based on Kernighan and Ritchie: "The C Programming Language". There does not seem to be a way to make this work in an LL(1) fashion, but this generates a "working" parser. */ /* The assignment operator is right associative. */ Expr (. Expression rhs; e = null; .) = LogOrExp [ '=' Expr (. e = new Assignment(e.MakeLvalue(), rhs); .) ] | "write" Expr (. e = new UnOp(Operator.WriteI, e); .) . LogOrExp (. Expression e2; .) = LogAndExp { "||" LogAndExp (. e = new BinOp(Operator.Or, e, e2); .) } . LogAndExp (. Expression e2; .) = EqualExp { "&&" EqualExp (. e = new BinOp(Operator.And, e, e2); .) } . EqualExp (. Expression e2; Operator op; .) = RelationExp { ( "==" (. op = Operator.Eq; .) | "!=" (. op = Operator.Ne; .) ) RelationExp (. e = new BinOp(op, e, e2); .) } . RelationExp (. Expression e2; Operator op; .) = AddExp { ( "<" (. op = Operator.Lt; .) | ">" (. op = Operator.Gt; .) | "<=" (. op = Operator.Le; .) | ">=" (. op = Operator.Ge; .) ) AddExp (. e = new BinOp(op, e, e2); .) } . AddExp (. Expression e2; Operator op; .) = MultExp { ( "+" (. op = Operator.Add; .) | "-" (. op = Operator.Sub; .) ) MultExp (. e = new BinOp(op, e, e2); .) } . MultExp (. Expression e2; Operator op; .) = UnaryExp { ( "*" (. op = Operator.Mul; .) | "/" (. op = Operator.Div; .) ) UnaryExp (. e = new BinOp(op, e, e2); .) } . UnaryExp (. Expression e1; e = null; .) = PostFixExp | "+" UnaryExp | "-" UnaryExp (. e = new UnOp(Operator.Neg, e1); .) | "!" UnaryExp (. e = new UnOp(Operator.Not, e1); .) | "*" UnaryExp (. e = new DereferenceAccess(e1); .) | "&" UnaryExp (. e = new AddressOf(e1.MakeLvalue()); .) . PostFixExp (. Expression e1; Expression[] es = new Expression[0]; .) = Primary [ "[" Expr (. e = new IndexAccess(e, e1); .) "]" | "(" [ ActualPars ] ")" (. VariableAccess varAcc = e as VariableAccess; if (varAcc != null) e = new Call(varAcc.name, es); else throw new Exception("Calling non-name expression"); .) ] . Primary (. String name; int n; e = null; .) = Ident (. e = new VariableAccess(name); .) | Number (. e = new Constant(n, Type.intType); .) | "(" Expr ")" . /* Function call arguments */ ActualPars (. Expression e; List eList = new List(); .) = Expr (. eList.Add(e); .) { "," Expr (. eList.Add(e); .) } (. es = eList.ToArray(); .) . END MicroC.