| /* |
| * 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; } |
| ; |
| |
| %% |