blob: 596b211352d6ae431080844f2f9b37b440c9a070 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
%{
#include "AST.h"
#include "Declaration.h"
#include "Type.h"
#include "VarDeclaration.h"
#include "FunctionDeclaration.h"
#include "CompositeDeclaration.h"
#include "Define.h"
#include "Include.h"
#include "EnumVarDeclaration.h"
#include "Note.h"
#include "TypeDef.h"
#include "Expression.h"
#include "c2hal_y.h"
#include <stdio.h>
#include <algorithm>
using namespace android;
extern int yylex(YYSTYPE *yylval_param, YYLTYPE *llocp, void *);
int yyerror(YYLTYPE *llocp, AST *, const char *s) {
extern bool should_report_errors;
if (!should_report_errors) {
return 0;
}
fflush(stdout);
LOG(ERROR) << " "
<< s
<< " near line "
<< llocp->first_line;
return 0;
}
#define scanner ast->scanner()
std::string get_last_comment() {
extern std::string last_comment;
std::string ret{last_comment};
// clear the last comment now that it's been taken
last_comment = "";
return ret;
}
%}
%parse-param { android::AST *ast }
%lex-param { void *scanner }
%locations
%pure-parser
%glr-parser
/* These have to do with the fact that
* struct_or_union_declaration and enum_declaration
* both start with STRUCT/UNION/ENUM opt_id
* and type_qualifiers contain these.
*/
%expect 3
%token START_HEADER
%token START_EXPR
%token STRUCT
%token UNION
%token ENUM
%token CLASS
%token CONST
%token VOID
%token INCLUDE
%token DEFINE
%token TYPEDEF
%token UNSIGNED
%token SIGNED
%token LSHIFT
%token RSHIFT
%token VARARGS
%token NAMESPACE
%token EXTERN
%token C_STRING
%left ','
%right '?' ':'
%left '|'
%left '^'
%left '&'
%left RSHIFT LSHIFT
%left '+' '-'
%left '*' '/' '%'
%right '~' '!' UMINUS UPLUS
%left ARRAY_SUBSCRIPT FUNCTION_CALL
%right STRUCT ENUM
%token<str> ID
%token<str> COMMENT
%token<str> VALUE
%token<str> INTEGRAL_VALUE
%token<str> INCLUDE_FILE
%token<str> FUNCTION
%token<str> DEFINE_SLURP
%token<str> OTHER_STATEMENT
%type<expression> array
%type<expressions> arrays
%type<expression> expr
%type<expressions> args
%type<type> type
%type<type> opt_enum_base_type
%type<qualifier> type_qualifier
%type<qualifiers> type_qualifiers
%type<declaration> declaration
%type<declarations> declarations
%type<composite> struct_or_union_declaration
%type<composite> enum_declaration
%type<param> param
%type<params> params
%type<qualification> struct_or_union
%type<str> opt_id
%type<include> include
%type<enum_var> enum_var
%type<declarations> enum_vars enum_vars_all_but_last
%type<declaration> enum_var_line enum_var_last_line
%start parse_selector
%union {
const char *str;
int count;
android::Declaration *declaration;
android::CompositeDeclaration *composite;
std::vector<android::Declaration *> *declarations;
android::EnumVarDeclaration *enum_var;
android::Declaration *param;
std::vector<android::Declaration *> *params;
android::Type *type;
android::Type::Qualifier *qualifier;
android::Type::Qualifier::Qualification qualification;
std::vector<android::Type::Qualifier*> *qualifiers;
android::Include *include;
std::vector<android::Include *> *includes;
android::Expression *expression;
std::vector<android::Expression *> *expressions;
}
%%
parse_selector
: START_HEADER header
| START_EXPR expr_parser
;
expr_parser
: expr
{
ast->setExpression($1);
}
;
header
: declarations /* well, we are a header file */
{
ast->setDeclarations($1);
}
;
declarations
: /* EMPTY */
{
$$ = new std::vector<Declaration *>;
}
| declarations declaration
{
$$ = $1;
$$->push_back($2);
}
| declarations EXTERN C_STRING '{' declarations '}'
{
$1->push_back(new Note("extern \"C\" { "));
$1->insert($1->end(), $5->begin(), $5->end());
$1->push_back(new Note("} // end of extern C"));
delete $5;
$$ = $1;
}
;
declaration
: param ';'
{
$$ = $1;
$$->setComment(get_last_comment());
}
| struct_or_union_declaration ';'
{
$$ = $1;
}
| enum_declaration ';'
{
$$ = $1;
}
| TYPEDEF struct_or_union_declaration ';'
{
// ignore that it is a typedef, for our purposes it doesn't matter
$$ = $2;
}
| TYPEDEF enum_declaration ';'
{
// ignore that it is a typedef, for our purposes it doesn't matter
$$ = $2;
}
| TYPEDEF param ';' /* looks like 'typedef const int8_t store;' */
{
$$ = new TypeDef($2->getName(), $2);
$$->setComment(get_last_comment());
}
| DEFINE ID DEFINE_SLURP
{
$$ = new Define($2, $3);
$$->setComment(get_last_comment());
}
| OTHER_STATEMENT
{
$$ = new Note($1);
$$->setComment(get_last_comment());
}
| FUNCTION
{
$$ = new Note($1);
$$->setComment(get_last_comment());
}
| type ID '=' expr ';'
{
$$ = new Note($1->decorateName($2) + " = " + $4->toString());
}
| include
{
$$ = $1;
$$->setComment(get_last_comment());
}
| NAMESPACE ID '{' declarations '}'
{
$$ = new CompositeDeclaration(Type::Qualifier::STRUCT,
$2,
$4);
get_last_comment(); // clear it
$$->setComment("/* from namespace declaration */");
}
;
include
: INCLUDE '<' INCLUDE_FILE '>'
{
$$ = new Include($3, true /* isLibrary */);
}
| INCLUDE '"' INCLUDE_FILE '"'
{
$$ = new Include($3, false /* isLibrary */);
}
;
struct_or_union_declaration
: struct_or_union opt_id
{
$<str>$ = strdup(get_last_comment().c_str());
}
'{' declarations '}' opt_id
{
$$ = new CompositeDeclaration($1, $2, $5);
$$->setComment($<str>3);
if(!std::string($7).empty()) {
$$->setName($7);
}
}
;
opt_comma
: /* EMPTY */
| ','
;
enum_key
: ENUM
| ENUM CLASS /* c++11 */
| ENUM STRUCT /* c++11 */
;
opt_enum_base_type
: /* EMPTY */ { $$ = NULL; }
| ':' type { $$ = $2; }
;
enum_declaration
: enum_key opt_id
{
$<str>$ = strdup(get_last_comment().c_str());
}
opt_enum_base_type '{' enum_vars '}' opt_id
{
$$ = new CompositeDeclaration(Type::Qualifier::ENUM, $2, $6);
$$->setComment($<str>3);
if($4) {
$$->setEnumTypeName($4->decorateName(""));
delete $4;
}
if(!std::string($8).empty()) {
$$->setName($8);
}
}
;
enum_vars
: /* EMPTY */
{
$$ = new std::vector<Declaration *>;
}
| enum_vars_all_but_last enum_var_last_line
{
$$ = $1;
$$->push_back($2);
}
enum_vars_all_but_last
: /* EMPTY */
{
$$ = new std::vector<Declaration *>;
}
| enum_vars_all_but_last enum_var_line
{
$$ = $1;
$$->push_back($2);
}
;
enum_var_last_line
: enum_var opt_comma { $$ = $1; }
| OTHER_STATEMENT
{
$$ = new Note($1);
$$->setComment(get_last_comment());
}
;
enum_var_line
: enum_var ',' { $$ = $1; }
| OTHER_STATEMENT
{
$$ = new Note($1);
$$->setComment(get_last_comment());
}
;
enum_var
: ID
{
$$ = new EnumVarDeclaration($1, NULL);
$$->setComment(get_last_comment());
}
| ID '=' expr
{
$$ = new EnumVarDeclaration($1, $3);
$$->setComment(get_last_comment());
}
;
params
: /* EMPTY */
{
$$ = new std::vector<Declaration *>;
}
| param
{
$$ = new std::vector<Declaration *>;
$$->push_back($1);
}
| params ',' param
{
$$ = $1;
$$->push_back($3);
}
;
param
: type arrays
{
$1->setArrays($2);
// allow for either "const int myvar" or "const int"
// as a parameter declaration
std::string lastId = $1->removeLastId();
$$ = new VarDeclaration($1, lastId);
}
| type '(' '*' ID arrays ')' '(' params ')'
{
$1->setArrays($5);
$$ = new FunctionDeclaration($1, $4, $8);
}
| type ID '(' params ')'
{
$$ = new FunctionDeclaration($1, $2, $4);
}
| type '(' ID ')' '(' params ')'
{
$$ = new FunctionDeclaration($1, $3, $6);
}
| VARARGS
{
$$ = new VarDeclaration(new Type(NULL), "...");
}
;
type
: type_qualifiers
{
$$ = new Type($1);
}
;
type_qualifiers
: type_qualifier
{
$$ = new std::vector<Type::Qualifier *>;
$$->push_back($1);
}
| type_qualifiers type_qualifier
{
$$ = $1;
$$->push_back($2);
}
;
opt_id
: /* EMPTY */ { $$ = ""; }
|
ID { $$ = $1; }
;
expr
: ID
{
$$ = Expression::atom(Expression::Type::UNKNOWN, $1, true /* isId*/ );
}
| VALUE { $$ = Expression::atom(Expression::Type::UNKNOWN, $1); }
| INTEGRAL_VALUE { $$ = Expression::atom(Expression::integralType($1), $1); }
| '(' expr ')' { $$ = Expression::parenthesize($2); }
| ID '[' expr ']' %prec ARRAY_SUBSCRIPT {
$$ = Expression::arraySubscript($1, $3);
}
| ID '(' args ')' %prec FUNCTION_CALL {
$$ = Expression::functionCall($1, $3);
}
| expr '?' expr ':' expr { $$ = Expression::ternary($1, $3, $5); }
| expr '+' expr { $$ = Expression::binary($1, "+", $3); }
| expr '-' expr { $$ = Expression::binary($1, "-", $3); }
| expr '/' expr { $$ = Expression::binary($1, "/", $3); }
| expr '*' expr { $$ = Expression::binary($1, "*", $3); }
| expr '%' expr { $$ = Expression::binary($1, "%%", $3); }
| expr '&' expr { $$ = Expression::binary($1, "&", $3); }
| expr '|' expr { $$ = Expression::binary($1, "|", $3); }
| expr '^' expr { $$ = Expression::binary($1, "^", $3); }
| expr LSHIFT expr { $$ = Expression::binary($1, "<<", $3); }
| expr RSHIFT expr { $$ = Expression::binary($1, ">>", $3); }
| '~' expr { $$ = Expression::unary("~", $2); }
| '-' expr %prec UMINUS { $$ = Expression::unary("-", $2); }
| '+' expr %prec UPLUS { $$ = Expression::unary("+", $2); }
;
args
: /* empty */
{
$$ = new std::vector<Expression *>;
}
| expr
{
$$ = new std::vector<Expression *>;
$$->push_back($1);
}
| args ',' expr
{
$$ = $1;
$$->push_back($3);
}
;
type_qualifier
: UNSIGNED { $$ = new Type::Qualifier(Type::Qualifier::UNSIGNED); }
| SIGNED { $$ = new Type::Qualifier(Type::Qualifier::SIGNED); }
| VOID { $$ = new Type::Qualifier(Type::Qualifier::VOID); }
| '*' { $$ = new Type::Qualifier(Type::Qualifier::POINTER); }
| CONST { $$ = new Type::Qualifier(Type::Qualifier::CONST); }
| ID { $$ = new Type::Qualifier(Type::Qualifier::ID, $1); }
| '<' type '>' { $$ = new Type::Qualifier(Type::Qualifier::GENERICS, $2); }
| enum_key { $$ = new Type::Qualifier(Type::Qualifier::ENUM); }
| struct_or_union { $$ = new Type::Qualifier($1); }
;
struct_or_union
: STRUCT { $$ = android::Type::Qualifier::STRUCT; }
| UNION { $$ = android::Type::Qualifier::UNION; }
;
arrays
: /* empty */ { $$ = new std::vector<Expression *>; }
| arrays array {
$$ = $1;
$$->push_back($2);
}
;
array
: '[' ']' { $$ = Expression::atom(Expression::Type::UNKNOWN, " "); }
| '[' expr ']' { $$ = $2; }
;
%%