Forum: Compiler & IDEs C: Variablen und Typen in ihre Basistypen zerlegen (YACC & Co?)


von A. S. (Gast)


Lesenswert?

Habe leider keine Erfahrung im Compilerbau, mit Lex oder YACC, daher die 
Frage, es geht um reines C (kein ++):

Ausgangslage: verschachtelte Strukturen, erstmal ohne Unions, 
Bitstrutkuren, Floats. Reine ANSI-C-Basistypen, also (un)signed 
(char|int|short|long) und z.B. gcc.
1
#pragma pack 4
2
typedef unsigned int tValue;
3
typedef struct
4
{
5
   unsigned char  Status;
6
   tValue         Value;
7
}tSet;
8
9
typedef struct
10
{
11
   const char *name;
12
   tSet       Set;
13
}tMeasure;
14
15
extern tMeasure Measure;

Measure hat aufgedröselt, bei 4 Byte für int und Zeiger, sowas wie:

 4 Byte Measure.name
 1 Byte Measure.Set.Status
 3 Byte ... (frei)
 4 Byte Measure.Set.Value.

Wie kommt man automatisiert an dieses "Layout" von Measure? Also Tear 
Down bis zu den Basistypen?

a) Mit Lex und Yacc und viel Arbeit?
b) Measure in einem Dummy-C/C++-File instanziiert und ein Output-File 
nach Assembler-Reservierungen parsen?

Die Typ-Verschachtelungen seine auf mehrere (h-)Files verteilt.

Auch ist es keine Option, die Struktur woanders zu beschreiben und 
daraus den C-Code (und alles weitere) zu erzeugen. Auch sei Portabilität 
hier kein Thema.

Gruß

achim

von Christopher J. (christopher_j23)


Lesenswert?

Ich würde dafür Clang bzw. libclang benutzen. Clang hat die Möglichkeit 
einen AST auszugeben und je nach wünschen zu filtern.
1
$ cat asdf.c
2
#pragma pack (4)
3
typedef unsigned int tValue;
4
typedef struct
5
{
6
   unsigned char  Status;
7
   tValue         Value;
8
}tSet;
9
10
typedef struct
11
{
12
   const char *name;
13
   tSet       Set;
14
}tMeasure;
15
16
tMeasure Measure;
1
$ clang -c -target arm-none-eabi -mcpu=cortex-m3 -Xclang -fdump-record-layouts asdf.c
2
3
*** Dumping AST Record Layout
4
         0 | tSet
5
         0 |   unsigned char Status
6
         4 |   tValue Value
7
           | [sizeof=8, align=4]
8
9
*** Dumping AST Record Layout
10
         0 | tMeasure
11
         0 |   const char * name
12
         4 |   tSet Set
13
         4 |     unsigned char Status
14
         8 |     tValue Value
15
           | [sizeof=12, align=4]
16
17
*** Dumping IRgen Record Layout
18
Record: RecordDecl 0x3b8afb0 <asdf.c:3:9, line:7:1> line:3:9 struct definition
19
|-MaxFieldAlignmentAttr 0x3b8b050 <<invalid sloc>> Implicit 32
20
|-FieldDecl 0x3b8b098 <line:5:4, col:19> col:19 Status 'unsigned char'
21
`-FieldDecl 0x3b8b110 <line:6:4, col:19> col:19 Value 'tValue':'unsigned int'
22
23
Layout: <CGRecordLayout
24
  LLVMType:%struct.tSet = type { i8, i32 }
25
  IsZeroInitializable:1
26
  BitFields:[
27
]>
28
29
*** Dumping IRgen Record Layout
30
Record: RecordDecl 0x3b8b218 <asdf.c:9:9, line:13:1> line:9:9 struct definition
31
|-MaxFieldAlignmentAttr 0x3b8b2c0 <<invalid sloc>> Implicit 32
32
|-FieldDecl 0x3b8b338 <line:11:4, col:16> col:16 name 'const char *'
33
`-FieldDecl 0x3b8b3b0 <line:12:4, col:15> col:15 Set 'tSet':'tSet'
34
35
Layout: <CGRecordLayout
36
  LLVMType:%struct.tMeasure = type { i8*, %struct.tSet }
37
  IsZeroInitializable:1
38
  BitFields:[
39
]>


Mit dem Aufruf von Clang mit "-Xclang -fdump-record-layouts" bekommst du 
ziemlich genau das was du wolltest in einer relativ einfach parsebaren 
Form. "-target arm-none-eabi" und "-mcpu=cortex-m3" ist lediglich um die 
Pointergröße auf die gewünschten 32bit zu stellen und "-c" um den Linker 
ruhig zu stellen (compile only).

Wenn du Sonderwünsche hast, dann kannst du die mit libclang umsetzen, 
was gewissermaßen das Clang-Frontend als Library ist. libclang wird auch 
in vielen Tools rund um C(++) genutzt, z.B. in QT-Creator oder 
YouCompleteMe für Autovervollständigung und Syntaxanalyse.

von A. S. (Gast)


Lesenswert?

vielen Dank Christopher.

Es scheint, also wäre das ein gangbarer Weg. Das reicht mir bisher, es 
wird dann in ein paar Monaten aktuell. Bis dahin kann ich die 
Bestrebungen, da was eigenes zu from Scratch zu frickeln, beruhigen.

von S. R. (svenska)


Lesenswert?

Achim S. schrieb:
> Wie kommt man automatisiert an dieses "Layout" von Measure? Also Tear
> Down bis zu den Basistypen?

Zur Laufzeit kannst du mit offsetof() und sizeof() die Struktur 
zerlegen, aber dazu musst du über alle Elemente iterieren können. 
Außerdem gibt es oft noch die Möglichkeit, das Layout vorher festzulegen 
(aligned/packed), statt es nachträglich auseinanderzufriemeln. ;-)

Wenn du den Compiler befragst, musst du bedenken, dass ein anderer 
Compiler (gcc!) oder andere Parameter das Layout ändern können. Es ist 
nicht unbedingt so statisch, wie du glaubst.

von Lalala (Gast)


Lesenswert?

Was ist denn das echte Problem, dass Du damit loesen moechtest? Warum 
muss das automatisch gehen?

Ansonsten Assemblerzwischencode vom compiler ausgeben lassen und 
reinsehen (lassen).

von Andreas M. (amesser)


Lesenswert?

Statt aufwänding die Ausgabe von clang zu parsen kann man auch einfach 
direkt die libclang in sein Programm einbinden, dann bekommt den AST 
direkt und kann sich durchhangeln. Das ist gar nicht so schwer.
Wir benutzen hier libclang aus python heraus um sämtliche C-Strukturen 
aus einem (oder mehren) C-Headern automatisiert in Python 
ctypes.Structure Klassendefinitionen umzusetzen. (Und natürlich parsen 
wir auch gleich die Aufrufparameter der C-Funktionen, Konstanten, 
Defines... aus den Headern und nutzen das dann um die C-Funktionen aus 
python heraus aufrufen zu können) Python packet zu clang heist 
"clang"...

von Le X. (lex_91)


Lesenswert?

Ähnlich dem libclang-Ansatz könntest du mit libelf und libdwarf an das 
.elf-File rangehen und über die Debuginformationen dir alle nötigen 
Infos beschaffen.

libdwarf (bzw. das dwarf-Format) war zwar nicht wirklich schön, aber hat 
funktioniert.
Ich musste damals auch Strukturen/Arrays zerlegen und brauchte außerdem 
die Adressen der Variablen/der einzelnen Member.


Aber der libclang-Ansatz sieht für deinen konkreten Zweck erstmal 
einfacher aus.

von Kaj (Gast)


Lesenswert?


Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.