1
0

struct-parser.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. const {
  2. createAliasMap,
  3. createEnumTypeMap,
  4. findEnums,
  5. findStruct,
  6. findStructs,
  7. normalizeLookupName,
  8. normalizeTypeText,
  9. parseDeclarator,
  10. splitDeclarators,
  11. stripComments
  12. } = require('./struct-c-syntax.js')
  13. const {
  14. parseStructFields
  15. } = require('./struct-layout.js')
  16. const STRUCT_VARIABLE_QUALIFIERS = {
  17. code: true,
  18. const: true,
  19. data: true,
  20. extern: true,
  21. idata: true,
  22. pdata: true,
  23. static: true,
  24. volatile: true,
  25. xdata: true
  26. }
  27. function parseStructDefinition(sourceText) {
  28. const source = stripComments(sourceText)
  29. const enums = findEnums(source)
  30. const enumTypes = createEnumTypeMap(enums)
  31. const aliases = createAliasMap(source, enums)
  32. const structInfo = findStruct(source)
  33. if (!structInfo) {
  34. throw new Error('未找到结构体定义')
  35. }
  36. const registers = parseStructFields(structInfo.body, aliases, enumTypes)
  37. if (!registers.length) {
  38. throw new Error('结构体中没有可识别的变量定义')
  39. }
  40. return {
  41. name: structInfo.name || 'Struct',
  42. registers,
  43. structName: structInfo.name || 'Struct'
  44. }
  45. }
  46. function getStructNameAliases(structInfo, aliases) {
  47. const names = [structInfo.name]
  48. if (structInfo.tagName) names.push(`struct ${structInfo.tagName}`)
  49. Object.keys(aliases || {}).forEach((aliasName) => {
  50. if (aliases[aliasName] === structInfo.name) names.push(aliasName)
  51. })
  52. return names.filter(Boolean)
  53. }
  54. function normalizeVariableTypeText(typeText, aliases) {
  55. const normalized = normalizeTypeText(typeText)
  56. if (!normalized) return ''
  57. const tokens = normalized
  58. .split(/\s+/)
  59. .filter((token) => !STRUCT_VARIABLE_QUALIFIERS[token])
  60. const compact = tokens.join(' ')
  61. if (aliases && aliases[compact]) return aliases[compact]
  62. return compact
  63. }
  64. function parseStructVariables(source, structs, aliases) {
  65. const variablesByName = {}
  66. structs.forEach((structInfo) => {
  67. const structNames = getStructNameAliases(structInfo, aliases)
  68. structNames.forEach((structName) => {
  69. const escaped = structName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
  70. const variablePattern = new RegExp(`(^|[;\\n{}])\\s*([A-Za-z_][\\w\\s]*?\\s+)?${escaped}\\s+([^;{}()]+);`, 'g')
  71. let match
  72. while ((match = variablePattern.exec(source))) {
  73. const prefix = normalizeVariableTypeText(match[2] || '', aliases)
  74. if (prefix) continue
  75. splitDeclarators(match[3]).forEach((declaratorText) => {
  76. const field = parseDeclarator(declaratorText)
  77. if (!field) return
  78. const variableInfo = {
  79. arrayDimensions: field.arrayDimensions,
  80. name: field.name,
  81. registers: structInfo.registers,
  82. structName: structInfo.name
  83. }
  84. variablesByName[field.name] = variableInfo
  85. variablesByName[field.name.replace(/^_+/, '').toLowerCase()] = variableInfo
  86. variablesByName[normalizeLookupName(field.name)] = variableInfo
  87. })
  88. }
  89. })
  90. })
  91. return variablesByName
  92. }
  93. function getEnumVariableTypeNames(enumInfo = {}) {
  94. return (Array.isArray(enumInfo.typeNames) ? enumInfo.typeNames : [])
  95. .concat(enumInfo.name, enumInfo.typedefName, enumInfo.tagName ? `enum ${enumInfo.tagName}` : '')
  96. .filter(Boolean)
  97. }
  98. function parseEnumVariables(source, enums, aliases) {
  99. const variablesByName = {}
  100. enums.forEach((enumInfo) => {
  101. getEnumVariableTypeNames(enumInfo).forEach((enumTypeName) => {
  102. const escaped = enumTypeName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
  103. const variablePattern = new RegExp(`(^|[;\\n{}])\\s*([A-Za-z_][\\w\\s]*?\\s+)?${escaped}\\s+([^;{}()]+);`, 'g')
  104. let match
  105. while ((match = variablePattern.exec(source))) {
  106. const prefix = normalizeVariableTypeText(match[2] || '', aliases)
  107. if (prefix) continue
  108. splitDeclarators(match[3]).forEach((declaratorText) => {
  109. const field = parseDeclarator(declaratorText)
  110. if (!field) return
  111. variablesByName[field.name] = enumInfo
  112. variablesByName[field.name.replace(/^_+/, '').toLowerCase()] = enumInfo
  113. variablesByName[normalizeLookupName(field.name)] = enumInfo
  114. })
  115. }
  116. })
  117. })
  118. return variablesByName
  119. }
  120. function parseStructCatalog(sourceText) {
  121. const source = stripComments(sourceText)
  122. const enums = findEnums(source)
  123. const enumTypes = createEnumTypeMap(enums)
  124. const aliases = createAliasMap(source, enums)
  125. const structs = findStructs(source).map((structInfo) => ({
  126. ...structInfo,
  127. registers: parseStructFields(structInfo.body, aliases, enumTypes)
  128. })).filter((structInfo) => structInfo.registers.length)
  129. if (!structs.length && !enums.length) {
  130. throw new Error('未找到可识别的结构体或枚举定义')
  131. }
  132. return {
  133. enums,
  134. enumVariablesByName: parseEnumVariables(source, enums, aliases),
  135. structs,
  136. variablesByName: parseStructVariables(source, structs, aliases)
  137. }
  138. }
  139. module.exports = {
  140. parseStructCatalog,
  141. parseStructDefinition,
  142. stripComments
  143. }