github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/ast/floating_literal.go (about) 1 package ast 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/Konstantin8105/c4go/preprocessor" 8 ) 9 10 // FloatingLiteral is type of float literal 11 type FloatingLiteral struct { 12 Addr Address 13 Pos Position 14 Type string 15 Value float64 16 ChildNodes []Node 17 } 18 19 func parseFloatingLiteral(line string) *FloatingLiteral { 20 groups := groupsFromRegex( 21 "<(?P<position>.*)> '(?P<type>.*?)' (?P<value>.+)", 22 line, 23 ) 24 25 return &FloatingLiteral{ 26 Addr: ParseAddress(groups["address"]), 27 Pos: NewPositionFromString(groups["position"]), 28 Type: groups["type"], 29 Value: atof(groups["value"]), 30 ChildNodes: []Node{}, 31 } 32 } 33 34 // AddChild adds a new child node. Child nodes can then be accessed with the 35 // Children attribute. 36 func (n *FloatingLiteral) AddChild(node Node) { 37 n.ChildNodes = append(n.ChildNodes, node) 38 } 39 40 // Address returns the numeric address of the node. See the documentation for 41 // the Address type for more information. 42 func (n *FloatingLiteral) Address() Address { 43 return n.Addr 44 } 45 46 // Children returns the child nodes. If this node does not have any children or 47 // this node does not support children it will always return an empty slice. 48 func (n *FloatingLiteral) Children() []Node { 49 return n.ChildNodes 50 } 51 52 // Position returns the position in the original source code. 53 func (n *FloatingLiteral) Position() Position { 54 return n.Pos 55 } 56 57 // FloatingLiteralError represents one instance of an error where the exact 58 // floating point value of a FloatingLiteral could not be determined from the 59 // original source. See RepairFloatingLiteralsFromSource for a full explanation. 60 type FloatingLiteralError struct { 61 Node *FloatingLiteral 62 Err error 63 } 64 65 // RepairFloatingLiteralsFromSource finds the exact values of floating literals 66 // by reading their values directly from the preprocessed source. 67 // 68 // The clang AST only serializes floating point values in scientific notation 69 // with 7 significant digits. This is not enough when dealing with precise 70 // numbers. 71 // 72 // The only solution is to read the original floating literal from the source 73 // code. We can do this by using the positional information on the node. 74 // 75 // If the floating literal cannot be resolved for any reason the original value 76 // will remain. This function will return all errors encountered. 77 func RepairFloatingLiteralsFromSource(rootNode Node, filePP preprocessor.FilePP) ( 78 errs []FloatingLiteralError) { 79 floatingLiteralNodes := 80 GetAllNodesOfType(rootNode, reflect.TypeOf((*FloatingLiteral)(nil))) 81 82 for _, node := range floatingLiteralNodes { 83 fNode := node.(*FloatingLiteral) 84 85 // Use the node position to retrieve the original line from the 86 // preprocessed source. 87 pos := node.Position() 88 89 b, err := filePP.GetSnippet(pos.File, 90 pos.Line, pos.LineEnd, 91 pos.Column, pos.ColumnEnd) 92 93 line := string(b) 94 95 // If there was a problem reading the line we should raise a warning and 96 // use the value we have. Hopefully that will be an accurate enough 97 // representation. 98 if err != nil { 99 errs = append(errs, FloatingLiteralError{Node: fNode, Err: err}) 100 } 101 102 fmt.Sscan(line, &fNode.Value) 103 } 104 105 return 106 }