From 22ef4a6b19db02fb92cb2dff4d8dd776fc8aba8a Mon Sep 17 00:00:00 2001 From: Konstantin8105 Date: Sat, 12 Oct 2019 18:01:01 +0300 Subject: [PATCH 1/3] IMPLICIT: create a valid test --- fortran/parser.go | 47 +++++++---- fortran/scan.go | 201 +++++++++++++++++++++++++++++----------------- testdata/main.f | 18 ++++- 3 files changed, 174 insertions(+), 92 deletions(-) diff --git a/fortran/parser.go b/fortran/parser.go index ea30effe..5f1a9d93 100644 --- a/fortran/parser.go +++ b/fortran/parser.go @@ -144,6 +144,11 @@ 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 @@ -151,6 +156,8 @@ type parser struct { Common common // share memory between subroutines + implicit []implicitVariable + functionExternalName []string initVars varInits // map of name to type @@ -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{}, @@ -1424,6 +1436,10 @@ func (p *parser) parseExternal() { } } +func (p *parser) resetImplicit() { + p.implicit = nil +} + func (p *parser) parseStmt() (stmts []goast.Stmt) { onlyForRecover := p.ident @@ -1569,27 +1585,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) diff --git a/fortran/scan.go b/fortran/scan.go index 3ad8b5ca..ade12fe2 100644 --- a/fortran/scan.go +++ b/fortran/scan.go @@ -92,6 +92,7 @@ func scan(b []byte) (ns []node) { for e := s.nodes.Front(); e != nil; e = e.Next() { ns = append(ns, *e.Value.(*node)) } + fmt.Println(ns) }() // separate lines @@ -696,12 +697,12 @@ 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++ @@ -712,95 +713,145 @@ impl: 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 { - break + + // 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 == 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 } - types = append(types, *(n.Value.(*node))) } - 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'} + for n := e.Next(); n != nil && n.Value.(*node).tok != ftNewLine; { + s.nodes.Remove(n.Prev()) } - if Debug { - fmt.Fprintf(os.Stdout, "finding next IMPLICIT... %d\n", iter) - } goto impl } diff --git a/testdata/main.f b/testdata/main.f index 3bbcf0ae..6d2c89a8 100644 --- a/testdata/main.f +++ b/testdata/main.f @@ -109,6 +109,9 @@ program MAIN call testName("test_implicit2") call test_implicit2() + call testName("test_implicit3") + call test_implicit3() + call testName("test_common") call test_common() @@ -1053,7 +1056,20 @@ SUBROUTINE test_implicit2 WRITE(*,'(I2)') X WRITE(*,'(I2)') Y WRITE(*,'(I2)') Z - END + END + + SUBROUTINE test_implicit3 + IMPLICIT INTEGER (A-C) + AQ = 5 + BQ = 8 + CQ = 1 + IF (AQ.NE. 5) call fail("implicit 1") + IF (BQ.NE. 8) call fail("implicit 2") + IF (CQ.NE. 1) call fail("implicit 3") + WRITE(*,'(I2)') AQ + WRITE(*,'(I2)') BQ + WRITE(*,'(I2)') CQ + END C ----------------------------------------------------- From 2b61e21c74f3b6ce376b287843c96f4a0ef00425 Mon Sep 17 00:00:00 2001 From: Konstantin8105 Date: Sun, 13 Oct 2019 00:04:04 +0300 Subject: [PATCH 2/3] IMPLICIT: add initialization --- fortran/parser.go | 41 +++++++++++++++++++++++++++++++++++++++++ fortran/scan.go | 14 +++++++++++--- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/fortran/parser.go b/fortran/parser.go index 5f1a9d93..27ebba43 100644 --- a/fortran/parser.go +++ b/fortran/parser.go @@ -1440,6 +1440,15 @@ 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 @@ -1684,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, diff --git a/fortran/scan.go b/fortran/scan.go index ade12fe2..714a13b6 100644 --- a/fortran/scan.go +++ b/fortran/scan.go @@ -92,7 +92,6 @@ func scan(b []byte) (ns []node) { for e := s.nodes.Front(); e != nil; e = e.Next() { ns = append(ns, *e.Value.(*node)) } - fmt.Println(ns) }() // separate lines @@ -708,6 +707,8 @@ 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 { @@ -720,6 +721,9 @@ impl: // 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 + } if n.Value.(*node).tok == token.COMMA && // , n.Prev().Value.(*node).tok == token.RPAREN { // ) // need split @@ -848,8 +852,12 @@ impl: for i := 0; i < len(inject); i++ { s.nodes.InsertBefore(&(inject[i]), e) } - for n := e.Next(); n != nil && n.Value.(*node).tok != ftNewLine; { - s.nodes.Remove(n.Prev()) + var rem []*list.Element + for n := e; n != nil && n.Value.(*node).tok != ftNewLine; n = n.Next() { + rem = append(rem, n) + } + for i := range rem { + s.nodes.Remove(rem[i]) } goto impl From c4ba1365532f458f77204a9d60535a9497ed97f9 Mon Sep 17 00:00:00 2001 From: Konstantin8105 Date: Sun, 13 Oct 2019 00:10:27 +0300 Subject: [PATCH 3/3] add todo for IMPLICIT --- testdata/main.f | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/testdata/main.f b/testdata/main.f index 6d2c89a8..37d30a0f 100644 --- a/testdata/main.f +++ b/testdata/main.f @@ -1060,17 +1060,26 @@ SUBROUTINE test_implicit2 SUBROUTINE test_implicit3 IMPLICIT INTEGER (A-C) +C IMPLICIT INTEGER (Z) AQ = 5 BQ = 8 CQ = 1 +C CALL INIT_Z(Z) IF (AQ.NE. 5) call fail("implicit 1") IF (BQ.NE. 8) call fail("implicit 2") IF (CQ.NE. 1) call fail("implicit 3") +C IF (Z .NE.42) call fail("implicit 4") WRITE(*,'(I2)') AQ WRITE(*,'(I2)') BQ WRITE(*,'(I2)') CQ +C WRITE(*,'(I2)') Z END +C SUBROUTINE INIT_Z(Z) +C INTEGER Z +C Z = 42 +C END + C ----------------------------------------------------- SUBROUTINE test_common