// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include "types.h" #include "syscall_parser.h" using std::string; using std::vector; bool is_identifier_keyword(const string& iden) { if (iden == "syscall" || iden == "returns" || iden == "optional" || iden == "IN" || iden == "OUT" || iden == "INOUT") { return true; } return false; } bool vet_identifier(const string& iden, const FileCtx& fc) { if (iden.empty()) { fc.print_error("expecting idenfier", ""); return false; } if (is_identifier_keyword(iden)) { fc.print_error("identifier cannot be keyword or attribute", iden); return false; } if (!isalpha(iden[0])) { fc.print_error("identifier should start with a-z|A-Z", string(iden)); return false; } return true; } bool parse_param_attributes(TokenStream* ts, vector* attrs) { while (ts->peek_next() != ")" && ts->peek_next() != ",") { auto attr = ts->next(); attrs->push_back(attr); } return true; } bool parse_product_of_identifiers(TokenStream* ts, TypeSpec* type_spec, std::vector* identifiers) { while (true) { if (!vet_identifier(ts->curr(), ts->filectx())) return false; if (ts->curr() == type_spec->name) { ts->filectx().print_error("invalid name for an array specifier", ts->curr()); return false; } identifiers->push_back(ts->curr()); if (ts->next() == "]") { return true; } if (ts->curr() != "*") { ts->filectx().print_error("expected ']' or '*'", ""); return false; } ts->next(); // consume '*' } } bool parse_arrayspec(TokenStream* ts, TypeSpec* type_spec) { uint32_t count = 0; std::vector multipliers; if (ts->next() != "[") return false; if (ts->next().empty()) return false; auto c = ts->curr()[0]; if (isalpha(c)) { if (!parse_product_of_identifiers(ts, type_spec, &multipliers)) { return false; } } else if (isdigit(c)) { count = c - '0'; if (ts->curr().size() > 1 || count == 0 || count > 9) { ts->filectx().print_error("only 1-9 explicit array count allowed", ""); return false; } if (ts->next() != "]") { ts->filectx().print_error("expected", "]"); return false; } } else { ts->filectx().print_error("expected array specifier", ""); return false; } type_spec->arr_spec.reset(new ArraySpec{ArraySpec::IN, count, multipliers}); return true; } bool parse_typespec(TokenStream* ts, TypeSpec* type_spec) { if (ts->peek_next() == ":") { auto name = ts->curr(); if (!vet_identifier(name, ts->filectx())) return false; type_spec->name = name; ts->next(); if (ts->next().empty()) return false; } auto type = ts->curr(); if (!vet_identifier(type, ts->filectx())) return false; type_spec->type = type; if (ts->peek_next() == "[" && !parse_arrayspec(ts, type_spec)) { return false; } if (!parse_param_attributes(ts, &type_spec->attributes)) { return false; } if (type_spec->arr_spec && !type_spec->arr_spec->assign_kind(type_spec->attributes)) { ts->filectx().print_error("expected", "IN, INOUT or OUT"); return false; } return true; } bool parse_argpack(TokenStream* ts, vector* v) { if (ts->curr() != "(") { ts->filectx().print_error("expected", "("); return false; } while (true) { if (ts->next() == ")") break; if (v->size() > 0) { if (ts->curr() != ",") { ts->filectx().print_error("expected", ", or :"); return false; } ts->next(); } TypeSpec type_spec; if (!parse_typespec(ts, &type_spec)) return false; v->emplace_back(std::move(type_spec)); } return true; } bool process_comment(AbigenGenerator* parser, TokenStream& ts) { return true; } bool process_syscall(AbigenGenerator* parser, TokenStream& ts) { auto name = ts.next(); if (!vet_identifier(name, ts.filectx())) return false; Syscall syscall{ts.filectx(), name}; // Every entry gets the special catch-all "*" attribute. syscall.attributes.push_back("*"); while (true) { auto maybe_attr = ts.next(); if (maybe_attr[0] != '(') { syscall.attributes.push_back(maybe_attr); } else { break; } } if (!parse_argpack(&ts, &syscall.arg_spec)) return false; auto return_spec = ts.next(); if (return_spec == "returns") { ts.next(); if (!parse_argpack(&ts, &syscall.ret_spec)) { return false; } if (syscall.ret_spec.size() > 1) { std::for_each(syscall.ret_spec.begin() + 1, syscall.ret_spec.end(), [](TypeSpec& type_spec) { type_spec.arr_spec.reset( new ArraySpec{ArraySpec::OUT, 1, {}}); }); } } else if (return_spec != ";") { ts.filectx().print_error("expected", ";"); return false; } return parser->AddSyscall(std::move(syscall)); }