Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IMPLICIT: names #23

Merged
merged 4 commits into from
Oct 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 72 additions & 16 deletions fortran/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,20 @@ func (c *common) addBlockName(name string, vars []string) {
c.mem[name] = vars
}

type implicitVariable struct {
symbol byte
typ []node
}

type parser struct {
ast goast.File
ident int
ns []node

Common common // share memory between subroutines

implicit []implicitVariable

functionExternalName []string

initVars varInits // map of name to type
Expand Down Expand Up @@ -944,6 +951,11 @@ func (p *parser) parseSubroutine() (decl goast.Decl) {
if Debug {
fmt.Fprintf(os.Stdout, "Parse subroutine\n")
}

defer func() {
p.resetImplicit()
}()

var fd goast.FuncDecl
fd.Type = &goast.FuncType{
Params: &goast.FieldList{},
Expand Down Expand Up @@ -1424,6 +1436,19 @@ func (p *parser) parseExternal() {
}
}

func (p *parser) resetImplicit() {
p.implicit = nil
}

func (p parser) isImplicit(b byte) (typ []node, ok bool) {
for i := range p.implicit {
if b == p.implicit[i].symbol {
return p.implicit[i].typ, true
}
}
return
}

func (p *parser) parseStmt() (stmts []goast.Stmt) {
onlyForRecover := p.ident

Expand Down Expand Up @@ -1569,27 +1594,26 @@ func (p *parser) parseStmt() (stmts []goast.Stmt) {

case ftImplicit:
// Examples:
// FROM:
// IMPLICIT DOUBLE PRECISION(A-H, O-Z)
// IMPLICIT INTEGER(I-N)
// TO:
// DOUBLE PRECISION A
// DOUBLE PRECISION ...
// DOUBLE PRECISION H
// INTEGER I
// INTEGER ...
// INTEGER N
// TODO: add support IMPLICIT
var nodes []node
// IMPLICIT DOUBLE PRECISION A
// IMPLICIT INTEGER B
//
// Only with one symbol name
p.expect(ftImplicit)
p.ident++

var typ []node
for ; p.ident < len(p.ns); p.ident++ {
if p.ns[p.ident].tok == ftNewLine || p.ns[p.ident].tok == token.EOF {
break
}
nodes = append(nodes, p.ns[p.ident])
typ = append(typ, p.ns[p.ident])
}
// p.addError("IMPLICIT is not support.\n" + nodesToString(nodes))
// ignore
_ = nodes
impl := implicitVariable{
symbol: typ[len(typ)-2].b[0],
typ: typ[:len(typ)-3],
}
p.implicit = append(p.implicit, impl)
p.expect(ftNewLine)

case token.INT:
labelName := string(p.ns[p.ident].b)
Expand Down Expand Up @@ -1669,6 +1693,38 @@ func (p *parser) parseStmt() (stmts []goast.Stmt) {
}

if isAssignStmt {
// IMPLICIT initialization
if v := p.ns[start]; v.tok == token.IDENT {
_, ok := p.initVars.get(string(v.b))
if !ok {
typ, ok := p.isImplicit(v.b[0])
if ok {
// add init
var inject []node
inject = append(inject, typ...)
for i := start; i < pos; i++ {
inject = append(inject, p.ns[i])
}
inject = append(inject, node{
tok: ftNewLine,
b: []byte{'\n'},
})
p.ns = append(p.ns[:start], append(inject, p.ns[start:]...)...)
old := p.ident
p.ident -= len(inject)
// s := p.parseStmt()
s := p.parseInit()
p.ident = old + len(inject)
if len(s) > 0 {
stmts = append(stmts, s...)
}
start += len(inject)
pos += len(inject)
}
}
}

// add assign
assign := goast.AssignStmt{
Lhs: []goast.Expr{p.parseExpr(start, pos)},
Tok: token.ASSIGN,
Expand Down
207 changes: 133 additions & 74 deletions fortran/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,111 +696,170 @@ multi:
// IMPLICIT INTEGER(I-N)
// IMPLICIT COMPLEX (U,V,W), CHARACTER*4 (C,S)
// TO:
// DOUBLE PRECISION A
// DOUBLE PRECISION ...
// DOUBLE PRECISION H
// INTEGER I
// INTEGER ...
// INTEGER N
// IMPLICIT DOUBLE PRECISION (A)
// IMPLICIT DOUBLE PRECISION ...
// IMPLICIT DOUBLE PRECISION (H)
// IMPLICIT INTEGER (I)
// IMPLICIT INTEGER ...
// IMPLICIT INTEGER (N)
iter := 0
impl:
iter++
if iter > 100000 {
panic(fmt.Errorf("Too many IMPLICIT iterations"))
} else if Debug {
fmt.Fprintf(os.Stdout, "finding next IMPLICIT... %d\n", iter)
}
for e := s.nodes.Front(); e != nil; e = e.Next() {
if e.Value.(*node).tok != ftImplicit {
continue
}
// record type nodes
var types []node
begin := e
n := e.Next()
for ; n != nil; n = n.Next() {
if n.Value.(*node).tok == token.LPAREN {

// split from:
// IMPLICIT COMPLEX (U,V,W), CHARACTER*4 (C,S)
// to:
// IMPLICIT COMPLEX (U,V,W)
// IMPLICIT CHARACTER*4 (C,S)
for n := e.Next(); n != nil; n = n.Next() {
if n.Value.(*node).tok == ftNewLine {
break
}
types = append(types, *(n.Value.(*node)))
if n.Value.(*node).tok == token.COMMA && // ,
n.Prev().Value.(*node).tok == token.RPAREN { // )
// need split
n.Value.(*node).tok = ftImplicit
n.Value.(*node).b = []byte("IMPLICIT")
s.nodes.InsertBefore(&node{
tok: ftNewLine,
b: []byte("\n"),
}, n)
goto impl
}
}
n = n.Next() // because n = LPAREN

// generate var names
var names []byte
for ; n != nil && n.Value.(*node).tok != token.RPAREN; n = n.Next() {
// split from:
// IMPLICIT COMPLEX (U,V,W)
// to:
// IMPLICIT COMPLEX (U)
// IMPLICIT COMPLEX (V)
// IMPLICIT COMPLEX (W)
// or
// IMPLICIT COMPLEX (A-C)
// to
// IMPLICIT COMPLEX (A,B,C)
haveRparen := false
var n *list.Element
for n = e.Next(); n != nil; n = n.Next() {
if n.Value.(*node).tok == ftNewLine {
if n.Prev().Value.(*node).tok == token.RPAREN {
haveRparen = true
}
break
}
}
if !haveRparen {
continue
}
var nodes []*node
n = n.Prev() // now RPAREN
withSub := false
for n = n.Prev(); n != nil; n = n.Prev() {
if n.Value.(*node).tok == token.COMMA {
continue
}
if n.Value.(*node).tok == token.SUB { // -
n = n.Next()
new := int(n.Value.(*node).b[0])
for ch := int(names[len(names)-1]) + 1; ch <= new; ch++ {
names = append(names, byte(ch))
}
withSub = true
n.Value.(*node).tok = token.COMMA
continue
}
names = append(names, n.Value.(*node).b[0])
if n.Value.(*node).tok == token.LPAREN {
break
}
nodes = append(nodes, n.Value.(*node))
}
if n == nil {
break
// reverse nodes
for left, right := 0, len(nodes)-1; left < right; left, right = left+1, right-1 {
nodes[left], nodes[right] = nodes[right], nodes[left]
}
n = n.Next() // because n = RPAREN

// inject code
var injectNodes []node
injectNodes = append(injectNodes, types...)
for i := 0; i < len(names); i++ {
injectNodes = append(injectNodes, node{
tok: token.IDENT,
b: []byte{names[i]},
pos: position{
line: e.Value.(*node).pos.line,
col: e.Value.(*node).pos.col,
},
})
if i != len(names)-1 {
injectNodes = append(injectNodes, node{
if len(nodes) == 1 {
continue
}
if withSub && len(nodes) == 2 {
// case :
// IMPLICIT COMPLEX (A-C)
// in nodes : [A C]
// transform for
// IMPLICIT COMPLEX (A,B,C)
var names []byte
for ch := int(nodes[0].b[0]) + 1; ch < int(nodes[1].b[0]); ch++ {
names = append(names, byte(ch))
}
for i := range names {
s.nodes.InsertAfter(&node{
tok: token.COMMA,
b: []byte{','},
pos: position{
line: e.Value.(*node).pos.line,
col: e.Value.(*node).pos.col,
},
})
}, n)
s.nodes.InsertAfter(&node{
tok: token.IDENT,
b: []byte{names[i]},
}, n)
}
goto impl
}
// IMPLICIT COMPLEX (U,V)
// to:
// IMPLICIT COMPLEX (U)
// IMPLICIT COMPLEX (V)

if n.Value.(*node).tok == token.COMMA {
// add IMPLICIT and goto impl
// Example:
// from:
// IMPLICIT COMPLEX (U,V,W), CHARACTER*4 (C,S)
// to:
// COMPLEX U,V,W
// IMPLICIT CHARACTER*4 (C,S)
injectNodes = append(injectNodes, node{
tok: ftNewLine,
b: []byte("\n"),
})
injectNodes = append(injectNodes, node{
tok: ftImplicit,
b: []byte("IMPLICIT"),
})
n = n.Next() // remove comma
// get type of variables
var typ []node
for n := e.Next(); n != nil; n = n.Next() {
if n.Value.(*node).tok == token.LPAREN {
break
}
typ = append(typ, *(n.Value.(*node)))
}
// generate inject nodes
var inject []node
for i := range nodes {
inject = append(inject,
node{
tok: ftImplicit,
b: []byte("IMPLICIT"),
},
)
inject = append(inject, typ...)
inject = append(inject,
node{
tok: token.LPAREN,
b: []byte{'('},
},
node{
tok: token.IDENT,
b: []byte{nodes[i].b[0]},
},
node{
tok: token.RPAREN,
b: []byte{')'},
},
node{
tok: ftNewLine,
b: []byte{'\n'},
},
)
}
injectNodes = append(injectNodes, *(n.Value.(*node)))

for i := len(injectNodes) - 1; i >= 0; i-- {
s.nodes.InsertAfter(&(injectNodes[i]), n)
// inject new code and remove old
for i := 0; i < len(inject); i++ {
s.nodes.InsertBefore(&(inject[i]), e)
}

for rem := begin; rem != nil && rem != n; rem = rem.Next() {
rem.Value.(*node).tok = ftNewLine
rem.Value.(*node).b = []byte{'\n'}
var rem []*list.Element
for n := e; n != nil && n.Value.(*node).tok != ftNewLine; n = n.Next() {
rem = append(rem, n)
}

if Debug {
fmt.Fprintf(os.Stdout, "finding next IMPLICIT... %d\n", iter)
for i := range rem {
s.nodes.Remove(rem[i])
}

goto impl
}

Expand Down
Loading