1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <algorithm> 6#include <string> 7#include <vector> 8 9#include "types.h" 10 11#include "syscall_parser.h" 12 13using std::string; 14using std::vector; 15 16bool is_identifier_keyword(const string& iden) { 17 if (iden == "syscall" || 18 iden == "returns" || 19 iden == "optional" || 20 iden == "IN" || iden == "OUT" || iden == "INOUT") { 21 return true; 22 } 23 return false; 24} 25 26bool vet_identifier(const string& iden, const FileCtx& fc) { 27 if (iden.empty()) { 28 fc.print_error("expecting idenfier", ""); 29 return false; 30 } 31 32 if (is_identifier_keyword(iden)) { 33 fc.print_error("identifier cannot be keyword or attribute", iden); 34 return false; 35 } 36 if (!isalpha(iden[0])) { 37 fc.print_error("identifier should start with a-z|A-Z", string(iden)); 38 return false; 39 } 40 return true; 41} 42 43bool parse_param_attributes(TokenStream* ts, vector<string>* attrs) { 44 while (ts->peek_next() != ")" && ts->peek_next() != ",") { 45 auto attr = ts->next(); 46 attrs->push_back(attr); 47 } 48 return true; 49} 50 51bool parse_product_of_identifiers(TokenStream* ts, TypeSpec* type_spec, 52 std::vector<std::string>* identifiers) { 53 while (true) { 54 if (!vet_identifier(ts->curr(), ts->filectx())) 55 return false; 56 if (ts->curr() == type_spec->name) { 57 ts->filectx().print_error("invalid name for an array specifier", ts->curr()); 58 return false; 59 } 60 identifiers->push_back(ts->curr()); 61 if (ts->next() == "]") { 62 return true; 63 } 64 if (ts->curr() != "*") { 65 ts->filectx().print_error("expected ']' or '*'", ""); 66 return false; 67 } 68 ts->next(); // consume '*' 69 } 70} 71 72bool parse_arrayspec(TokenStream* ts, TypeSpec* type_spec) { 73 uint32_t count = 0; 74 std::vector<std::string> multipliers; 75 76 if (ts->next() != "[") 77 return false; 78 79 if (ts->next().empty()) 80 return false; 81 82 auto c = ts->curr()[0]; 83 84 if (isalpha(c)) { 85 if (!parse_product_of_identifiers(ts, type_spec, &multipliers)) { 86 return false; 87 } 88 } else if (isdigit(c)) { 89 count = c - '0'; 90 if (ts->curr().size() > 1 || count == 0 || count > 9) { 91 ts->filectx().print_error("only 1-9 explicit array count allowed", ""); 92 return false; 93 } 94 if (ts->next() != "]") { 95 ts->filectx().print_error("expected", "]"); 96 return false; 97 } 98 } else { 99 ts->filectx().print_error("expected array specifier", ""); 100 return false; 101 } 102 type_spec->arr_spec.reset(new ArraySpec{ArraySpec::IN, count, multipliers}); 103 return true; 104} 105 106bool parse_typespec(TokenStream* ts, TypeSpec* type_spec) { 107 if (ts->peek_next() == ":") { 108 auto name = ts->curr(); 109 if (!vet_identifier(name, ts->filectx())) 110 return false; 111 112 type_spec->name = name; 113 114 ts->next(); 115 if (ts->next().empty()) 116 return false; 117 } 118 119 auto type = ts->curr(); 120 if (!vet_identifier(type, ts->filectx())) 121 return false; 122 123 type_spec->type = type; 124 125 if (ts->peek_next() == "[" && !parse_arrayspec(ts, type_spec)) { 126 return false; 127 } 128 129 if (!parse_param_attributes(ts, &type_spec->attributes)) { 130 return false; 131 } 132 133 if (type_spec->arr_spec && !type_spec->arr_spec->assign_kind(type_spec->attributes)) { 134 ts->filectx().print_error("expected", "IN, INOUT or OUT"); 135 return false; 136 } 137 return true; 138} 139 140bool parse_argpack(TokenStream* ts, vector<TypeSpec>* v) { 141 if (ts->curr() != "(") { 142 ts->filectx().print_error("expected", "("); 143 return false; 144 } 145 146 while (true) { 147 if (ts->next() == ")") 148 break; 149 150 if (v->size() > 0) { 151 if (ts->curr() != ",") { 152 ts->filectx().print_error("expected", ", or :"); 153 return false; 154 } 155 ts->next(); 156 } 157 158 TypeSpec type_spec; 159 160 if (!parse_typespec(ts, &type_spec)) 161 return false; 162 v->emplace_back(std::move(type_spec)); 163 } 164 return true; 165} 166 167bool process_comment(AbigenGenerator* parser, TokenStream& ts) { 168 return true; 169} 170 171bool process_syscall(AbigenGenerator* parser, TokenStream& ts) { 172 auto name = ts.next(); 173 174 if (!vet_identifier(name, ts.filectx())) 175 return false; 176 177 Syscall syscall{ts.filectx(), name}; 178 179 // Every entry gets the special catch-all "*" attribute. 180 syscall.attributes.push_back("*"); 181 182 while (true) { 183 auto maybe_attr = ts.next(); 184 if (maybe_attr[0] != '(') { 185 syscall.attributes.push_back(maybe_attr); 186 } else { 187 break; 188 } 189 } 190 191 if (!parse_argpack(&ts, &syscall.arg_spec)) 192 return false; 193 194 auto return_spec = ts.next(); 195 196 if (return_spec == "returns") { 197 ts.next(); 198 199 if (!parse_argpack(&ts, &syscall.ret_spec)) { 200 return false; 201 } 202 if (syscall.ret_spec.size() > 1) { 203 std::for_each(syscall.ret_spec.begin() + 1, syscall.ret_spec.end(), 204 [](TypeSpec& type_spec) { 205 type_spec.arr_spec.reset( 206 new ArraySpec{ArraySpec::OUT, 1, {}}); 207 }); 208 } 209 } else if (return_spec != ";") { 210 ts.filectx().print_error("expected", ";"); 211 return false; 212 } 213 214 return parser->AddSyscall(std::move(syscall)); 215} 216