1
0

struct-c-syntax.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. const TYPE_ALIASES = {
  2. bit: 'uint8_t',
  3. bool: 'uint8_t',
  4. char: 'int8_t',
  5. double: 'float',
  6. float: 'float',
  7. int: 'int16_t',
  8. int8: 'int8_t',
  9. int8_t: 'int8_t',
  10. int16: 'int16_t',
  11. int16_t: 'int16_t',
  12. int32: 'int32_t',
  13. int32_t: 'int32_t',
  14. long: 'int32_t',
  15. short: 'int16_t',
  16. 'signed char': 'int8_t',
  17. 'signed int': 'int16_t',
  18. 'signed long': 'int32_t',
  19. 'signed short': 'int16_t',
  20. uint8: 'uint8_t',
  21. uint8_t: 'uint8_t',
  22. uint16: 'uint16_t',
  23. uint16_t: 'uint16_t',
  24. uint32: 'uint32_t',
  25. uint32_t: 'uint32_t',
  26. 'unsigned char': 'uint8_t',
  27. 'unsigned int': 'uint16_t',
  28. 'unsigned long': 'uint32_t',
  29. 'unsigned short': 'uint16_t'
  30. }
  31. const TYPE_QUALIFIERS = {
  32. _I: true,
  33. _IO: true,
  34. _O: true,
  35. const: true,
  36. extern: true,
  37. register: true,
  38. static: true,
  39. volatile: true
  40. }
  41. const STRUCT_PATTERNS = [
  42. /typedef\s+struct(?:\s+[A-Za-z_]\w*)?\s*\{([\s\S]*?)\}\s*([A-Za-z_]\w*)\s*;/g,
  43. /struct\s+([A-Za-z_]\w*)\s*\{([\s\S]*?)\}\s*;/g
  44. ]
  45. function normalizeLookupName(value) {
  46. return String(value || '')
  47. .replace(/^_+/, '')
  48. .replace(/[^A-Za-z0-9]/g, '')
  49. .toLowerCase()
  50. }
  51. function stripComments(source) {
  52. return String(source || '')
  53. .replace(/\/\*[\s\S]*?\*\//g, '')
  54. .replace(/\/\/.*$/gm, '')
  55. }
  56. function normalizeTypeText(typeText) {
  57. return String(typeText || '')
  58. .replace(/\*/g, ' ')
  59. .replace(/\s+/g, ' ')
  60. .trim()
  61. }
  62. function resolveType(typeText, aliases) {
  63. const normalized = normalizeTypeText(typeText)
  64. if (!normalized) return ''
  65. const compact = normalized
  66. .split(/\s+/)
  67. .filter((token) => !TYPE_QUALIFIERS[token])
  68. .join(' ')
  69. .trim()
  70. if (!compact || /^struct\b/.test(compact) || /^enum\b/.test(compact) || compact.indexOf('*') >= 0) {
  71. return ''
  72. }
  73. if (aliases[compact]) return aliases[compact]
  74. const tokens = compact.split(/\s+/).filter(Boolean)
  75. for (const token of tokens) {
  76. if (aliases[token]) return aliases[token]
  77. }
  78. return ''
  79. }
  80. function createAliasMap(source) {
  81. const aliases = {
  82. ...TYPE_ALIASES
  83. }
  84. const definePattern = /^\s*#\s*define\s+([A-Za-z_]\w*)\s+([A-Za-z_]\w*)\s*$/gm
  85. let defineMatch
  86. while ((defineMatch = definePattern.exec(source))) {
  87. const name = defineMatch[1]
  88. const value = defineMatch[2]
  89. if (aliases[value]) aliases[name] = aliases[value]
  90. }
  91. const typedefPattern = /typedef\s+(?!struct\b)([^;{}]+?)\s+([A-Za-z_]\w*)\s*;/g
  92. let typedefMatch
  93. while ((typedefMatch = typedefPattern.exec(source))) {
  94. const resolvedType = resolveType(typedefMatch[1], aliases)
  95. if (resolvedType) aliases[typedefMatch[2]] = resolvedType
  96. }
  97. const typedefStructPattern = /typedef\s+struct(?:\s+([A-Za-z_]\w*))?\s*\{[\s\S]*?\}\s*([A-Za-z_]\w*)\s*;/g
  98. let structTypedefMatch
  99. while ((structTypedefMatch = typedefStructPattern.exec(source))) {
  100. const tagName = structTypedefMatch[1]
  101. const typedefName = structTypedefMatch[2]
  102. if (tagName && typedefName) aliases[`struct ${tagName}`] = typedefName
  103. }
  104. return aliases
  105. }
  106. function findStruct(source) {
  107. for (const pattern of STRUCT_PATTERNS) {
  108. pattern.lastIndex = 0
  109. const match = pattern.exec(source)
  110. if (!match) continue
  111. if (pattern === STRUCT_PATTERNS[0]) {
  112. return {
  113. body: match[1],
  114. name: match[2]
  115. }
  116. }
  117. return {
  118. body: match[2],
  119. name: match[1]
  120. }
  121. }
  122. return null
  123. }
  124. function findStructs(source) {
  125. const structs = []
  126. STRUCT_PATTERNS.forEach((pattern) => {
  127. pattern.lastIndex = 0
  128. let match
  129. while ((match = pattern.exec(source))) {
  130. if (pattern === STRUCT_PATTERNS[0]) {
  131. structs.push({
  132. body: match[1],
  133. name: match[2]
  134. })
  135. } else {
  136. structs.push({
  137. body: match[2],
  138. name: match[1],
  139. tagName: match[1]
  140. })
  141. }
  142. }
  143. })
  144. const seen = {}
  145. return structs.filter((item) => {
  146. const key = item.name
  147. if (!key || seen[key]) return false
  148. seen[key] = true
  149. return true
  150. })
  151. }
  152. function parseArrayDimensions(suffix) {
  153. const dimensions = []
  154. const pattern = /\[([^\]]*)\]/g
  155. let match
  156. while ((match = pattern.exec(suffix || ''))) {
  157. const text = String(match[1] || '').trim()
  158. const value = Number(text)
  159. if (!Number.isInteger(value) || value < 1) {
  160. throw new Error('数组长度需为正整数')
  161. }
  162. dimensions.push(value)
  163. }
  164. return dimensions
  165. }
  166. function splitDeclarations(body) {
  167. return String(body || '')
  168. .split(';')
  169. .map((item) => item.trim())
  170. .filter(Boolean)
  171. }
  172. function splitDeclarators(statement) {
  173. return String(statement || '')
  174. .split(',')
  175. .map((item) => item.trim())
  176. .filter(Boolean)
  177. }
  178. function parseFirstDeclarator(text) {
  179. const match = String(text || '').match(/^(.+?)\s+(\**\s*(?:[A-Za-z_]\w*)?(?:\s*\[[^\]]*\])*(?:\s*:\s*\d+)?)$/)
  180. if (!match) return null
  181. return {
  182. declarator: match[2],
  183. typeText: match[1]
  184. }
  185. }
  186. function parseDeclarator(text) {
  187. const rawText = String(text || '')
  188. const bitWidthMatch = rawText.match(/:\s*(\d+)\s*$/)
  189. const cleaned = rawText
  190. .replace(/=.*/, '')
  191. .replace(/:\s*\d+\s*$/, '')
  192. .replace(/\*/g, '')
  193. .trim()
  194. if (!cleaned && bitWidthMatch) {
  195. return {
  196. arrayDimensions: [],
  197. bitWidth: Number(bitWidthMatch[1]),
  198. name: ''
  199. }
  200. }
  201. const match = cleaned.match(/^([A-Za-z_]\w*)\s*((?:\[[^\]]*\])*)$/)
  202. if (!match) return null
  203. return {
  204. arrayDimensions: parseArrayDimensions(match[2]),
  205. bitWidth: bitWidthMatch ? Number(bitWidthMatch[1]) : null,
  206. name: match[1]
  207. }
  208. }
  209. module.exports = {
  210. createAliasMap,
  211. findStruct,
  212. findStructs,
  213. normalizeLookupName,
  214. normalizeTypeText,
  215. parseDeclarator,
  216. parseFirstDeclarator,
  217. resolveType,
  218. splitDeclarations,
  219. splitDeclarators,
  220. stripComments
  221. }